Title: [283178] trunk/Source/bmalloc
Revision
283178
Author
fpi...@apple.com
Date
2021-09-28 09:59:52 -0700 (Tue, 28 Sep 2021)

Log Message

[libpas] Fix coalescing of the large sharing pool and make it easy to introspect it (update to e4d20851ee9ff00f2962b349a9ff8465695a83d7)
https://bugs.webkit.org/show_bug.cgi?id=230867

Reviewed by Yusuke Suzuki.

This adds the ability to enable the libpas status reporter, adds a large sharing pool dump to
the status report, and fixes a large sharing pool coalescing bug found by doing that. Previously
we weren't coalescing things that are not free+committed.

Also updates the export script that I use to keep the libpas git repo in sync with what's in WK.

The large sharing pool is the mechanism by which libpas can find memory that can be decommitted
across isolated large heaps, even if those large heaps share pages with one another. The main
data structure is a red-black tree of nodes that represent memory ranges. If there are two
adjacent ranges of memory that are both fully live and committed or both decommitted, then we
want those to be represented using a single node. That wasn't quite working right. Even the
libpas test for this was testing the wrong thing. This fixes the behavior and the test. It's
perf-neutral since large heaps usually have a small number of objects in them anyway.

The new status reporting functionality can be enabled with the WebKitPasStatusReporter
environment variable. This takes an integer that tells the amount of data in the report. Here
are the recognized values:

1 - just report number of heaps
2 - something in between 1 and 3
3 - report everything that the status reporter can report right now (per-page data for
    segregated/bitfit heaps, lots of details for large heaps)

If the status reporter ever reported per-object information, it would be at level 4 or higher.
It's safe to pass 9999 or whatever if you just want the maximum report that libpas supports.
TL;DR for now you usually want WebKitPasStatusReporter=3.

* bmalloc/Environment.cpp:
(bmalloc::Environment::Environment):
* libpas/export.rb: Added.
* libpas/export.sh: Removed.
* libpas/src/libpas/pas_bitfit_directory.c:
(pas_bitfit_directory_construct): I needed to rationalize how we initialize disabled directories to make status reporting work.
(pas_bitfit_directory_get_first_free_view):
* libpas/src/libpas/pas_large_sharing_pool.c:
(states_match):
* libpas/src/libpas/pas_status_reporter.c:
(pas_status_reporter_dump_bitfit_directory):
(dump_large_sharing_pool_node_callback):
(pas_status_reporter_dump_large_sharing_pool):
(pas_status_reporter_dump_everything):
* libpas/src/libpas/pas_status_reporter.h:
* libpas/src/test/LargeSharingPoolDump.cpp:
* libpas/src/test/LargeSharingPoolDump.h:
* libpas/src/test/LargeSharingPoolTests.cpp:
(std::Range::Range):
(std::Range::operator== const):
(std::Range::operator!= const):
(std::operator<<):
(std::assertState):
(std::testGoodCoalesceEpochUpdate):
(addLargeSharingPoolTests):
(std::testBadCoalesceEpochUpdate): Deleted.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/bmalloc/ChangeLog (283177 => 283178)


--- trunk/Source/bmalloc/ChangeLog	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/ChangeLog	2021-09-28 16:59:52 UTC (rev 283178)
@@ -1,3 +1,64 @@
+2021-09-27  Filip Pizlo  <fpi...@apple.com>
+
+        [libpas] Fix coalescing of the large sharing pool and make it easy to introspect it (update to e4d20851ee9ff00f2962b349a9ff8465695a83d7)
+        https://bugs.webkit.org/show_bug.cgi?id=230867
+
+        Reviewed by Yusuke Suzuki.
+
+        This adds the ability to enable the libpas status reporter, adds a large sharing pool dump to
+        the status report, and fixes a large sharing pool coalescing bug found by doing that. Previously
+        we weren't coalescing things that are not free+committed.
+
+        Also updates the export script that I use to keep the libpas git repo in sync with what's in WK.
+
+        The large sharing pool is the mechanism by which libpas can find memory that can be decommitted
+        across isolated large heaps, even if those large heaps share pages with one another. The main
+        data structure is a red-black tree of nodes that represent memory ranges. If there are two
+        adjacent ranges of memory that are both fully live and committed or both decommitted, then we
+        want those to be represented using a single node. That wasn't quite working right. Even the
+        libpas test for this was testing the wrong thing. This fixes the behavior and the test. It's
+        perf-neutral since large heaps usually have a small number of objects in them anyway.
+
+        The new status reporting functionality can be enabled with the WebKitPasStatusReporter
+        environment variable. This takes an integer that tells the amount of data in the report. Here
+        are the recognized values:
+
+        1 - just report number of heaps
+        2 - something in between 1 and 3
+        3 - report everything that the status reporter can report right now (per-page data for
+            segregated/bitfit heaps, lots of details for large heaps)
+
+        If the status reporter ever reported per-object information, it would be at level 4 or higher.
+        It's safe to pass 9999 or whatever if you just want the maximum report that libpas supports.
+        TL;DR for now you usually want WebKitPasStatusReporter=3.
+
+        * bmalloc/Environment.cpp:
+        (bmalloc::Environment::Environment):
+        * libpas/export.rb: Added.
+        * libpas/export.sh: Removed.
+        * libpas/src/libpas/pas_bitfit_directory.c:
+        (pas_bitfit_directory_construct): I needed to rationalize how we initialize disabled directories to make status reporting work.
+        (pas_bitfit_directory_get_first_free_view):
+        * libpas/src/libpas/pas_large_sharing_pool.c:
+        (states_match):
+        * libpas/src/libpas/pas_status_reporter.c:
+        (pas_status_reporter_dump_bitfit_directory):
+        (dump_large_sharing_pool_node_callback):
+        (pas_status_reporter_dump_large_sharing_pool):
+        (pas_status_reporter_dump_everything):
+        * libpas/src/libpas/pas_status_reporter.h:
+        * libpas/src/test/LargeSharingPoolDump.cpp:
+        * libpas/src/test/LargeSharingPoolDump.h:
+        * libpas/src/test/LargeSharingPoolTests.cpp:
+        (std::Range::Range):
+        (std::Range::operator== const):
+        (std::Range::operator!= const):
+        (std::operator<<):
+        (std::assertState):
+        (std::testGoodCoalesceEpochUpdate):
+        (addLargeSharingPoolTests):
+        (std::testBadCoalesceEpochUpdate): Deleted.
+
 2021-09-22  Filip Pizlo  <fpi...@apple.com>
 
         [libpas] fix DebugHeap

Modified: trunk/Source/bmalloc/bmalloc/Environment.cpp (283177 => 283178)


--- trunk/Source/bmalloc/bmalloc/Environment.cpp	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/bmalloc/Environment.cpp	2021-09-28 16:59:52 UTC (rev 283178)
@@ -49,6 +49,10 @@
 }
 #endif
 
+#if BUSE(LIBPAS)
+#include "pas_status_reporter.h"
+#endif
+
 namespace bmalloc {
 
 static bool isMallocEnvironmentVariableSet()
@@ -136,6 +140,14 @@
 Environment::Environment(const LockHolder&)
     : m_isDebugHeapEnabled(computeIsDebugHeapEnabled())
 {
+#if BUSE(LIBPAS)
+    const char* statusReporter = getenv("WebKitPasStatusReporter");
+    if (statusReporter) {
+        unsigned enabled;
+        if (sscanf(statusReporter, "%u", &enabled) == 1)
+            pas_status_reporter_enabled = enabled;
+    }
+#endif
 }
 
 bool Environment::computeIsDebugHeapEnabled()

Added: trunk/Source/bmalloc/libpas/export.rb (0 => 283178)


--- trunk/Source/bmalloc/libpas/export.rb	                        (rev 0)
+++ trunk/Source/bmalloc/libpas/export.rb	2021-09-28 16:59:52 UTC (rev 283178)
@@ -0,0 +1,121 @@
+#!/usr/bin/env ruby
+# Copyright (c) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer. 
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution. 
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+require 'fileutils'
+require 'getoptlong'
+require 'pathname'
+
+opts = GetoptLong.new(
+    [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
+    [ '--force', '-f', GetoptLong::NO_ARGUMENT ]
+)
+
+$force = false
+
+opts.each {
+    | opt, arg |
+    case opt
+    when '--help'
+        puts "Usage: ./export.rb [-f] <destination>"
+        puts
+        puts "Copies local git checkout (including unstaged changes to files in the repo) to the"
+        puts "destination. Must be run in the repo's directory (the directory that contains this"
+        puts "script). Does not change the timestamp of files that did not change."
+        puts
+        puts "Options:"
+        puts "--help (-h)     Print this message."
+        puts "--force (-f)    Copy to the destination even if it doesn't look like a libpas directory."
+        exit 0
+
+    when '--force'
+        $force = true
+
+    else
+        raise
+    end
+}
+
+raise "Bad argument; see --help" unless ARGV.length == 1
+
+$destination = Pathname.new(ARGV[0]).realpath
+
+unless Pathname.new("src/libpas").directory?
+    puts "Error: must run this script from a libpas directory."
+    exit 1
+end
+
+unless ($destination + "src/libpas").directory?
+    if $force
+        puts "Warning: destination does not look like a libpas directory."
+    else
+        puts "Error: destination does not look like a libpas directory; use --force to override."
+        exit 1
+    end
+end
+
+def prepareDirectory(directory)
+    return if directory.directory?
+    raise if directory.to_s == "."
+    raise if directory.to_s.length <= $destination.to_s.length
+    prepareDirectory(directory.dirname)
+    puts "Preparing directory #{directory}"
+    FileUtils.rm_rf(directory)
+    directory.mkdir
+end
+
+IO.popen("git ls-files", "r") {
+    | inp |
+    inp.each_line {
+        | line |
+        line.chomp!
+        inputFile = Pathname.new(line)
+
+        raise if inputFile.directory?
+        
+        outputFile = $destination + line
+
+        contents = inputFile.read
+
+        if outputFile.exist? and
+          inputFile.directory? == outputFile.directory? and
+          inputFile.executable? == outputFile.executable? and
+          contents == outputFile.read
+            #puts "Skipping #{line}"
+            next
+        end
+
+        puts "Copying #{line} to #{outputFile}"
+
+        prepareDirectory(outputFile.dirname)
+
+        FileUtils.rm_rf(outputFile)
+        outputFile.write(contents)
+
+        outputFile.chmod(0755) if inputFile.executable?
+    }
+}
+
+raise unless $? == 0
+
+
Property changes on: trunk/Source/bmalloc/libpas/export.rb
___________________________________________________________________

Added: svn:executable

+* \ No newline at end of property

Deleted: trunk/Source/bmalloc/libpas/export.sh (283177 => 283178)


--- trunk/Source/bmalloc/libpas/export.sh	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/export.sh	2021-09-28 16:59:52 UTC (rev 283178)
@@ -1,39 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2021 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1.  Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer. 
-# 2.  Redistributions in binary form must reproduce the above copyright
-#     notice, this list of conditions and the following disclaimer in the
-#     documentation and/or other materials provided with the distribution. 
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS ``AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-set -e
-set -x
-
-rm -rf libpas-export
-git clone . libpas-export
-rm -rf libpas-export/.git
-
-where=$1
-
-if [ "x$where" != "x" ]
-then
-    ditto libpas-export $where
-    rm -rf libpas-export
-fi
-

Modified: trunk/Source/bmalloc/libpas/src/libpas/pas_bitfit_directory.c (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/libpas/pas_bitfit_directory.c	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/libpas/pas_bitfit_directory.c	2021-09-28 16:59:52 UTC (rev 283178)
@@ -46,6 +46,10 @@
 {
     static const bool verbose = false;
 
+    /* NOTE - this works even if the config is disabled, and produces a directory that is empty and
+       does nothing. This makes sense because it makes it easy to iterate over the directories in a heap
+       without knowing what your config is. */
+
     if (verbose)
         pas_log("Creating directory %p\n", directory);
     
@@ -54,7 +58,7 @@
     pas_bitfit_directory_max_free_vector_construct(&directory->max_frees);
     pas_bitfit_directory_view_vector_construct(&directory->views);
     pas_compact_atomic_bitfit_size_class_ptr_store(&directory->largest_size_class, NULL);
-    directory->config_kind = config->kind;
+    directory->config_kind = config->base.is_enabled ? config->kind : pas_bitfit_page_config_kind_null;
 
     directory->heap = heap;
     pas_bitfit_directory_segmented_bitvectors_construct(&directory->bitvectors);
@@ -62,7 +66,7 @@
 
     /* We could have been lazy about this - but it's probably not super necessary since the point
        of bitfit global directories is that there won't be too many of them. */
-    if (pas_bitfit_directory_does_sharing(directory)) {
+    if (config->base.is_enabled && pas_bitfit_directory_does_sharing(directory)) {
         pas_page_sharing_pool_add(
             &pas_physical_page_sharing_pool,
             pas_page_sharing_participant_create(
@@ -102,6 +106,8 @@
                                          pas_bitfit_page_config* page_config)
 {
     static const bool verbose = false;
+
+    PAS_ASSERT(page_config->base.is_enabled);
     
     for (;;) {
         pas_found_index found_index;

Modified: trunk/Source/bmalloc/libpas/src/libpas/pas_large_sharing_pool.c (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/libpas/pas_large_sharing_pool.c	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/libpas/pas_large_sharing_pool.c	2021-09-28 16:59:52 UTC (rev 283178)
@@ -287,13 +287,39 @@
 static bool states_match(pas_large_sharing_node* left,
                          pas_large_sharing_node* right)
 {
-    return left->is_committed == right->is_committed
-        && left->synchronization_style == right->synchronization_style
-        && ((!left->num_live_bytes && !right->num_live_bytes) ||
-            (pas_range_size(left->range) == left->num_live_bytes &&
-             pas_range_size(right->range) == right->num_live_bytes))
-        && (left->use_epoch == right->use_epoch
-            || (!left->is_committed && !left->num_live_bytes));
+    bool both_empty;
+    bool both_full;
+    
+    if (left->is_committed != right->is_committed)
+        return false;
+
+    if (left->synchronization_style != right->synchronization_style)
+        return false;
+
+    both_empty =
+        !left->num_live_bytes &&
+        !right->num_live_bytes;
+    
+    both_full =
+        pas_range_size(left->range) == left->num_live_bytes &&
+        pas_range_size(right->range) == right->num_live_bytes;
+
+    if (!both_empty && !both_full)
+        return false;
+
+    /* Right now: both sides have identical commit states and identical synchronization styes. And
+       either both sides are empty or both sides are full.
+    
+       The only reason why we wouldn't want to coalesce is if epochs didn't match. But that only
+       matters when the memory is free and committed. */
+
+    if (!left->is_committed)
+        return true;
+
+    if (both_full)
+        return true;
+
+    return left->use_epoch == right->use_epoch;
 }
 
 static bool is_eligible(pas_large_sharing_node* node)

Modified: trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.c (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.c	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.c	2021-09-28 16:59:52 UTC (rev 283178)
@@ -45,6 +45,7 @@
 #include "pas_heap_table.h"
 #include "pas_large_heap.h"
 #include "pas_large_map.h"
+#include "pas_large_sharing_pool.h"
 #include "pas_large_utility_free_heap.h"
 #include "pas_log.h"
 #include "pas_page_sharing_pool.h"
@@ -196,6 +197,9 @@
 void pas_status_reporter_dump_bitfit_directory(
     pas_stream* stream, pas_bitfit_directory* directory)
 {
+    if (directory->config_kind == pas_bitfit_page_config_kind_null)
+        return;
+    
     pas_stream_printf(stream, "            %s Global Dir (%p): ",
                       pas_bitfit_page_config_variant_get_capitalized_string(
                           pas_bitfit_page_config_kind_get_config(directory->config_kind)->variant),
@@ -644,6 +648,39 @@
     pas_stream_printf(stream, "\n");
 }
 
+static bool dump_large_sharing_pool_node_callback(pas_large_sharing_node* node,
+                                                  void* arg)
+{
+    pas_stream* stream;
+
+    stream = arg;
+
+    pas_stream_printf(stream, "        %p...%p: %s, %zu/%zu live (%.0lf%%), %llu",
+                      (void*)node->range.begin,
+                      (void*)node->range.end,
+                      pas_commit_mode_get_string(node->is_committed),
+                      node->num_live_bytes,
+                      pas_range_size(node->range),
+                      100. * (double)node->num_live_bytes / (double)pas_range_size(node->range),
+                      node->use_epoch);
+
+    if (node->synchronization_style != pas_physical_memory_is_locked_by_virtual_range_common_lock) {
+        pas_stream_printf(
+            stream, ", %s",
+            pas_physical_memory_synchronization_style_get_string(node->synchronization_style));
+    }
+
+    pas_stream_printf(stream, "\n");
+
+    return true;
+}
+
+void pas_status_reporter_dump_large_sharing_pool(pas_stream* stream)
+{
+    pas_stream_printf(stream, "    Large sharing pool contents:\n");
+    pas_large_sharing_pool_for_each(dump_large_sharing_pool_node_callback, stream, pas_lock_is_held);
+}
+
 void pas_status_reporter_dump_utility_heap(pas_stream* stream)
 {
     pas_stream_printf(stream, "    Utility Heap:\n");
@@ -958,6 +995,10 @@
     pas_status_reporter_dump_all_heaps(stream);
     pas_status_reporter_dump_all_shared_page_directories(stream);
     pas_status_reporter_dump_all_heaps_non_utility_summaries(stream);
+    
+    if (pas_status_reporter_enabled >= 3)
+        pas_status_reporter_dump_large_sharing_pool(stream);
+    
     pas_status_reporter_dump_utility_heap(stream);
 
     if (pas_status_reporter_enabled >= 3) {

Modified: trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.h (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.h	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/libpas/pas_status_reporter.h	2021-09-28 16:59:52 UTC (rev 283178)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2019-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -68,6 +68,7 @@
 PAS_API void pas_status_reporter_dump_all_heaps(pas_stream* stream);
 PAS_API void pas_status_reporter_dump_all_shared_page_directories(pas_stream* stream);
 PAS_API void pas_status_reporter_dump_all_heaps_non_utility_summaries(pas_stream* stream);
+PAS_API void pas_status_reporter_dump_large_sharing_pool(pas_stream* stream);
 PAS_API void pas_status_reporter_dump_utility_heap(pas_stream* stream);
 PAS_API void pas_status_reporter_dump_total_fragmentation(pas_stream* stream);
 PAS_API void pas_status_reporter_dump_tier_up_rates(pas_stream* stream);

Modified: trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.cpp (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.cpp	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.cpp	2021-09-28 16:59:52 UTC (rev 283178)
@@ -49,6 +49,16 @@
     pas_large_sharing_pool_for_each(forEachAdapter, &visitor, pas_lock_is_not_held);
 }
 
+vector<pas_large_sharing_node*> largeSharingPoolAsVector()
+{
+    vector<pas_large_sharing_node*> result;
+    forEachLargeSharingPoolNode([&] (pas_large_sharing_node* node) -> bool {
+        result.push_back(node);
+        return true;
+    });
+    return result;
+}
+
 void dumpLargeSharingPool()
 {
     cout << "Large sharing pool:\n";

Modified: trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.h (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.h	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolDump.h	2021-09-28 16:59:52 UTC (rev 283178)
@@ -31,8 +31,10 @@
 
 #include <functional>
 #include "pas_large_sharing_pool.h"
+#include <vector>
 
 void forEachLargeSharingPoolNode(std::function<bool(pas_large_sharing_node*)> visitor);
+std::vector<pas_large_sharing_node*> largeSharingPoolAsVector();
 void dumpLargeSharingPool();
 
 #endif // TLC

Modified: trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolTests.cpp (283177 => 283178)


--- trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolTests.cpp	2021-09-28 16:55:51 UTC (rev 283177)
+++ trunk/Source/bmalloc/libpas/src/test/LargeSharingPoolTests.cpp	2021-09-28 16:59:52 UTC (rev 283178)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
+ * Copyright (c) 2018-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -56,6 +56,26 @@
         , epoch(epoch)
     {
     }
+
+    explicit Range(pas_large_sharing_node* node)
+        : begin(node->range.begin)
+        , end(node->range.end)
+        , isCommitted(node->is_committed)
+        , numLiveBytes(node->num_live_bytes)
+        , epoch(node->use_epoch)
+    {
+    }
+
+    bool operator==(Range other) const
+    {
+        return begin == other.begin
+            && end == other.end
+            && isCommitted == other.isCommitted
+            && numLiveBytes == other.numLiveBytes
+            && epoch == other.epoch;
+    }
+
+    bool operator!=(Range other) const { return !(*this == other); }
     
     uintptr_t begin;
     uintptr_t end;
@@ -64,24 +84,51 @@
     uint64_t epoch;
 };
 
+ostream& operator<<(ostream& out, Range range)
+{
+    out << reinterpret_cast<void*>(range.begin) << "..." << reinterpret_cast<void*>(range.end)
+        << ", " << (range.isCommitted ? "committed" : "decommitted") << ", "
+        << range.numLiveBytes << "/" << (range.end - range.begin) << ", " << range.epoch;
+    return out;
+}
+
 void assertState(const vector<Range>& ranges)
 {
-    size_t index = 0;
-    forEachLargeSharingPoolNode(
-        [&] (pas_large_sharing_node* node) -> bool {
-            CHECK_LESS(index, ranges.size());
-            Range expectedRange = ranges[index++];
-            CHECK_EQUAL(node->range.begin, expectedRange.begin);
-            CHECK_EQUAL(node->range.end, expectedRange.end);
-            CHECK_EQUAL(node->is_committed, expectedRange.isCommitted);
-            CHECK_EQUAL(node->num_live_bytes, expectedRange.numLiveBytes);
-            CHECK_EQUAL(node->use_epoch, expectedRange.epoch);
-            return true;
-        });
-    CHECK_EQUAL(index, ranges.size());
+    vector<pas_large_sharing_node*> nodes = largeSharingPoolAsVector();
+    
+    bool allGood = true;
+
+    if (nodes.size() != ranges.size()) {
+        cout << "State does not match because we expected " << ranges.size() << " ranges but got "
+             << nodes.size() << " ranges.\n";
+        allGood = false;
+    } else {
+        for (size_t index = 0; index < nodes.size(); ++index) {
+            pas_large_sharing_node* node = nodes[index];
+            Range actualRange(node);
+            Range expectedRange = ranges[index];
+            if (expectedRange != actualRange) {
+                cout << "State does not match at index " << index << ": expected:\n"
+                     << "    " << expectedRange << ", but got:\n"
+                     << "    " << actualRange << "\n";
+                allGood = false;
+            }
+        }
+    }
+
+    if (!allGood) {
+        cout << "Got mismatch in states. Expected the state to be:\n";
+        for (Range range : ranges)
+            cout << "    " << range << "\n";
+        cout << "But got:\n";
+        for (pas_large_sharing_node* node : nodes)
+            cout << "    " << Range(node) << "\n";
+    }
+
+    CHECK(allGood);
 }
 
-void testBadCoalesceEpochUpdate()
+void testGoodCoalesceEpochUpdate()
 {
     static constexpr bool verbose = false;
     
@@ -123,10 +170,7 @@
     if (verbose)
         dumpLargeSharingPool();
 
-    assertState({ Range(0, 10 * PG, pas_committed, 10 * PG, 0),
-                  Range(10 * PG, 30 * PG, pas_committed, 20 * PG, 3),
-                  Range(30 * PG, END, pas_committed, END - 30 * PG, 0) });
-    
+    assertState({ Range(0, END, pas_committed, END, 3) });
 }
 
 } // anonymous namespace
@@ -138,7 +182,7 @@
 #if TLC
     EpochIsCounter epochIsCounter;
     
-    ADD_TEST(testBadCoalesceEpochUpdate());
+    ADD_TEST(testGoodCoalesceEpochUpdate());
 #endif // TLC
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to