src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7208
7baf47cb97cb
child 7535
7ae4e26cb1e0
child 8439
b857e4abb00c
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

tschatzl@5204 1 /*
tschatzl@5204 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
tschatzl@5204 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
tschatzl@5204 4 *
tschatzl@5204 5 * This code is free software; you can redistribute it and/or modify it
tschatzl@5204 6 * under the terms of the GNU General Public License version 2 only, as
tschatzl@5204 7 * published by the Free Software Foundation.
tschatzl@5204 8 *
tschatzl@5204 9 * This code is distributed in the hope that it will be useful, but WITHOUT
tschatzl@5204 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
tschatzl@5204 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
tschatzl@5204 12 * version 2 for more details (a copy is included in the LICENSE file that
tschatzl@5204 13 * accompanied this code).
tschatzl@5204 14 *
tschatzl@5204 15 * You should have received a copy of the GNU General Public License version
tschatzl@5204 16 * 2 along with this work; if not, write to the Free Software Foundation,
tschatzl@5204 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
tschatzl@5204 18 *
tschatzl@5204 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
tschatzl@5204 20 * or visit www.oracle.com if you need additional information or have any
tschatzl@5204 21 * questions.
tschatzl@5204 22 *
tschatzl@5204 23 */
tschatzl@5204 24
tschatzl@5204 25 #include "precompiled.hpp"
tschatzl@5204 26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
tschatzl@5204 27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
tschatzl@5204 28 #include "gc_implementation/g1/heapRegion.hpp"
tschatzl@5204 29 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
tschatzl@5204 30 #include "gc_implementation/g1/g1RemSet.inline.hpp"
tschatzl@5204 31 #include "gc_implementation/g1/g1RemSetSummary.hpp"
tschatzl@5204 32 #include "gc_implementation/g1/heapRegionRemSet.hpp"
tschatzl@5204 33 #include "runtime/thread.inline.hpp"
tschatzl@5204 34
tschatzl@5204 35 class GetRSThreadVTimeClosure : public ThreadClosure {
tschatzl@5204 36 private:
tschatzl@5204 37 G1RemSetSummary* _summary;
tschatzl@5204 38 uint _counter;
tschatzl@5204 39
tschatzl@5204 40 public:
tschatzl@5204 41 GetRSThreadVTimeClosure(G1RemSetSummary * summary) : ThreadClosure(), _summary(summary), _counter(0) {
tschatzl@5204 42 assert(_summary != NULL, "just checking");
tschatzl@5204 43 }
tschatzl@5204 44
tschatzl@5204 45 virtual void do_thread(Thread* t) {
tschatzl@5204 46 ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t;
tschatzl@5204 47 _summary->set_rs_thread_vtime(_counter, crt->vtime_accum());
tschatzl@5204 48 _counter++;
tschatzl@5204 49 }
tschatzl@5204 50 };
tschatzl@5204 51
tschatzl@5204 52 void G1RemSetSummary::update() {
tschatzl@5204 53 _num_refined_cards = remset()->conc_refine_cards();
tschatzl@5204 54 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
tschatzl@5204 55 _num_processed_buf_mutator = dcqs.processed_buffers_mut();
tschatzl@5204 56 _num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread();
tschatzl@5204 57
tschatzl@5204 58 _num_coarsenings = HeapRegionRemSet::n_coarsenings();
tschatzl@5204 59
tschatzl@5204 60 ConcurrentG1Refine * cg1r = G1CollectedHeap::heap()->concurrent_g1_refine();
tschatzl@5204 61 if (_rs_threads_vtimes != NULL) {
tschatzl@5204 62 GetRSThreadVTimeClosure p(this);
tschatzl@5204 63 cg1r->worker_threads_do(&p);
tschatzl@5204 64 }
tschatzl@5204 65 set_sampling_thread_vtime(cg1r->sampling_thread()->vtime_accum());
tschatzl@5204 66 }
tschatzl@5204 67
tschatzl@5204 68 void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) {
tschatzl@5204 69 assert(_rs_threads_vtimes != NULL, "just checking");
tschatzl@5204 70 assert(thread < _num_vtimes, "just checking");
tschatzl@5204 71 _rs_threads_vtimes[thread] = value;
tschatzl@5204 72 }
tschatzl@5204 73
tschatzl@5204 74 double G1RemSetSummary::rs_thread_vtime(uint thread) const {
tschatzl@5204 75 assert(_rs_threads_vtimes != NULL, "just checking");
tschatzl@5204 76 assert(thread < _num_vtimes, "just checking");
tschatzl@5204 77 return _rs_threads_vtimes[thread];
tschatzl@5204 78 }
tschatzl@5204 79
tschatzl@5812 80 void G1RemSetSummary::initialize(G1RemSet* remset) {
tschatzl@5204 81 assert(_rs_threads_vtimes == NULL, "just checking");
tschatzl@5204 82 assert(remset != NULL, "just checking");
tschatzl@5204 83
tschatzl@5204 84 _remset = remset;
tschatzl@5812 85 _num_vtimes = ConcurrentG1Refine::thread_num();
tschatzl@5204 86 _rs_threads_vtimes = NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC);
tschatzl@5204 87 memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes);
tschatzl@5204 88
tschatzl@5204 89 update();
tschatzl@5204 90 }
tschatzl@5204 91
tschatzl@5204 92 void G1RemSetSummary::set(G1RemSetSummary* other) {
tschatzl@5204 93 assert(other != NULL, "just checking");
tschatzl@5204 94 assert(remset() == other->remset(), "just checking");
tschatzl@5204 95 assert(_num_vtimes == other->_num_vtimes, "just checking");
tschatzl@5204 96
tschatzl@5204 97 _num_refined_cards = other->num_concurrent_refined_cards();
tschatzl@5204 98
tschatzl@5204 99 _num_processed_buf_mutator = other->num_processed_buf_mutator();
tschatzl@5204 100 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads();
tschatzl@5204 101
tschatzl@5204 102 _num_coarsenings = other->_num_coarsenings;
tschatzl@5204 103
tschatzl@5204 104 memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes);
tschatzl@5204 105
tschatzl@5204 106 set_sampling_thread_vtime(other->sampling_thread_vtime());
tschatzl@5204 107 }
tschatzl@5204 108
tschatzl@5204 109 void G1RemSetSummary::subtract_from(G1RemSetSummary* other) {
tschatzl@5204 110 assert(other != NULL, "just checking");
tschatzl@5204 111 assert(remset() == other->remset(), "just checking");
tschatzl@5204 112 assert(_num_vtimes == other->_num_vtimes, "just checking");
tschatzl@5204 113
tschatzl@5204 114 _num_refined_cards = other->num_concurrent_refined_cards() - _num_refined_cards;
tschatzl@5204 115
tschatzl@5204 116 _num_processed_buf_mutator = other->num_processed_buf_mutator() - _num_processed_buf_mutator;
tschatzl@5204 117 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads() - _num_processed_buf_rs_threads;
tschatzl@5204 118
tschatzl@5204 119 _num_coarsenings = other->num_coarsenings() - _num_coarsenings;
tschatzl@5204 120
tschatzl@5204 121 for (uint i = 0; i < _num_vtimes; i++) {
tschatzl@5204 122 set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i));
tschatzl@5204 123 }
tschatzl@5204 124
tschatzl@5204 125 _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime;
tschatzl@5204 126 }
tschatzl@5204 127
tschatzl@5807 128 static double percent_of(size_t numerator, size_t denominator) {
tschatzl@5807 129 if (denominator != 0) {
tschatzl@5807 130 return (double)numerator / denominator * 100.0f;
tschatzl@5807 131 } else {
tschatzl@5807 132 return 0.0f;
tschatzl@5807 133 }
tschatzl@5807 134 }
tschatzl@5807 135
tschatzl@5807 136 static size_t round_to_K(size_t value) {
tschatzl@5807 137 return value / K;
tschatzl@5807 138 }
tschatzl@5807 139
tschatzl@5807 140 class RegionTypeCounter VALUE_OBJ_CLASS_SPEC {
tschatzl@5807 141 private:
tschatzl@5807 142 const char* _name;
tschatzl@5807 143
tschatzl@5807 144 size_t _rs_mem_size;
tschatzl@5807 145 size_t _cards_occupied;
tschatzl@5807 146 size_t _amount;
tschatzl@5807 147
tschatzl@5807 148 size_t _code_root_mem_size;
tschatzl@5807 149 size_t _code_root_elems;
tschatzl@5807 150
tschatzl@5807 151 double rs_mem_size_percent_of(size_t total) {
tschatzl@5807 152 return percent_of(_rs_mem_size, total);
tschatzl@5807 153 }
tschatzl@5807 154
tschatzl@5807 155 double cards_occupied_percent_of(size_t total) {
tschatzl@5807 156 return percent_of(_cards_occupied, total);
tschatzl@5807 157 }
tschatzl@5807 158
tschatzl@5807 159 double code_root_mem_size_percent_of(size_t total) {
tschatzl@5807 160 return percent_of(_code_root_mem_size, total);
tschatzl@5807 161 }
tschatzl@5807 162
tschatzl@5807 163 double code_root_elems_percent_of(size_t total) {
tschatzl@5807 164 return percent_of(_code_root_elems, total);
tschatzl@5807 165 }
tschatzl@5807 166
tschatzl@5807 167 size_t amount() const { return _amount; }
tschatzl@5807 168
tschatzl@5807 169 public:
tschatzl@5807 170
tschatzl@5807 171 RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0),
tschatzl@5807 172 _amount(0), _code_root_mem_size(0), _code_root_elems(0) { }
tschatzl@5807 173
tschatzl@5807 174 void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size,
tschatzl@5807 175 size_t code_root_elems) {
tschatzl@5807 176 _rs_mem_size += rs_mem_size;
tschatzl@5807 177 _cards_occupied += cards_occupied;
tschatzl@5807 178 _code_root_mem_size += code_root_mem_size;
tschatzl@5807 179 _code_root_elems += code_root_elems;
tschatzl@5807 180 _amount++;
tschatzl@5807 181 }
tschatzl@5807 182
tschatzl@5807 183 size_t rs_mem_size() const { return _rs_mem_size; }
tschatzl@5807 184 size_t cards_occupied() const { return _cards_occupied; }
tschatzl@5807 185
tschatzl@5807 186 size_t code_root_mem_size() const { return _code_root_mem_size; }
tschatzl@5807 187 size_t code_root_elems() const { return _code_root_elems; }
tschatzl@5807 188
tschatzl@5807 189 void print_rs_mem_info_on(outputStream * out, size_t total) {
sjohanss@6009 190 out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
sjohanss@6009 191 round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name);
tschatzl@5807 192 }
tschatzl@5807 193
tschatzl@5807 194 void print_cards_occupied_info_on(outputStream * out, size_t total) {
sjohanss@6009 195 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) entries by "SIZE_FORMAT" %s regions",
sjohanss@6009 196 cards_occupied(), cards_occupied_percent_of(total), amount(), _name);
tschatzl@5807 197 }
tschatzl@5807 198
tschatzl@5807 199 void print_code_root_mem_info_on(outputStream * out, size_t total) {
sjohanss@6009 200 out->print_cr(" "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
sjohanss@6009 201 round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name);
tschatzl@5807 202 }
tschatzl@5807 203
tschatzl@5807 204 void print_code_root_elems_info_on(outputStream * out, size_t total) {
sjohanss@6009 205 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) elements by "SIZE_FORMAT" %s regions",
sjohanss@6009 206 code_root_elems(), code_root_elems_percent_of(total), amount(), _name);
tschatzl@5807 207 }
tschatzl@5807 208 };
tschatzl@5807 209
tschatzl@5807 210
tschatzl@5204 211 class HRRSStatsIter: public HeapRegionClosure {
tschatzl@5807 212 private:
tschatzl@5807 213 RegionTypeCounter _young;
tschatzl@5807 214 RegionTypeCounter _humonguous;
tschatzl@5807 215 RegionTypeCounter _free;
tschatzl@5807 216 RegionTypeCounter _old;
tschatzl@5807 217 RegionTypeCounter _all;
johnc@5548 218
johnc@5548 219 size_t _max_rs_mem_sz;
johnc@5548 220 HeapRegion* _max_rs_mem_sz_region;
johnc@5548 221
tschatzl@5807 222 size_t total_rs_mem_sz() const { return _all.rs_mem_size(); }
tschatzl@5807 223 size_t total_cards_occupied() const { return _all.cards_occupied(); }
tschatzl@5807 224
tschatzl@5807 225 size_t max_rs_mem_sz() const { return _max_rs_mem_sz; }
tschatzl@5807 226 HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; }
tschatzl@5807 227
johnc@5548 228 size_t _max_code_root_mem_sz;
johnc@5548 229 HeapRegion* _max_code_root_mem_sz_region;
tschatzl@5807 230
tschatzl@5807 231 size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); }
tschatzl@5807 232 size_t total_code_root_elems() const { return _all.code_root_elems(); }
tschatzl@5807 233
tschatzl@5807 234 size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; }
tschatzl@5807 235 HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; }
tschatzl@5807 236
tschatzl@5204 237 public:
tschatzl@5807 238 HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"),
tschatzl@5807 239 _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL),
tschatzl@5807 240 _max_rs_mem_sz(0), _max_code_root_mem_sz(0)
tschatzl@5204 241 {}
tschatzl@5204 242
tschatzl@5204 243 bool doHeapRegion(HeapRegion* r) {
johnc@5548 244 HeapRegionRemSet* hrrs = r->rem_set();
johnc@5548 245
johnc@5548 246 // HeapRegionRemSet::mem_size() includes the
johnc@5548 247 // size of the strong code roots
johnc@5548 248 size_t rs_mem_sz = hrrs->mem_size();
johnc@5548 249 if (rs_mem_sz > _max_rs_mem_sz) {
johnc@5548 250 _max_rs_mem_sz = rs_mem_sz;
johnc@5548 251 _max_rs_mem_sz_region = r;
tschatzl@5204 252 }
tschatzl@5807 253 size_t occupied_cards = hrrs->occupied();
johnc@5548 254 size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size();
tschatzl@5807 255 if (code_root_mem_sz > max_code_root_mem_sz()) {
mgerdin@7208 256 _max_code_root_mem_sz = code_root_mem_sz;
johnc@5548 257 _max_code_root_mem_sz_region = r;
johnc@5548 258 }
tschatzl@5807 259 size_t code_root_elems = hrrs->strong_code_roots_list_length();
johnc@5548 260
tschatzl@5807 261 RegionTypeCounter* current = NULL;
brutisso@7195 262 if (r->is_free()) {
brutisso@7195 263 current = &_free;
brutisso@7195 264 } else if (r->is_young()) {
tschatzl@5807 265 current = &_young;
tschatzl@5807 266 } else if (r->isHumongous()) {
tschatzl@5807 267 current = &_humonguous;
brutisso@7195 268 } else if (r->is_old()) {
brutisso@7195 269 current = &_old;
tschatzl@5807 270 } else {
brutisso@7195 271 ShouldNotReachHere();
tschatzl@5807 272 }
tschatzl@5807 273 current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
tschatzl@5807 274 _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
tschatzl@5807 275
tschatzl@5204 276 return false;
tschatzl@5204 277 }
tschatzl@5807 278
tschatzl@5807 279 void print_summary_on(outputStream* out) {
tschatzl@5807 280 RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL };
tschatzl@5807 281
tschatzl@5807 282 out->print_cr("\n Current rem set statistics");
tschatzl@5807 283 out->print_cr(" Total per region rem sets sizes = "SIZE_FORMAT"K."
tschatzl@5807 284 " Max = "SIZE_FORMAT"K.",
tschatzl@5807 285 round_to_K(total_rs_mem_sz()), round_to_K(max_rs_mem_sz()));
tschatzl@5807 286 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
tschatzl@5807 287 (*current)->print_rs_mem_info_on(out, total_rs_mem_sz());
tschatzl@5807 288 }
tschatzl@5807 289
tschatzl@5807 290 out->print_cr(" Static structures = "SIZE_FORMAT"K,"
tschatzl@5807 291 " free_lists = "SIZE_FORMAT"K.",
tschatzl@5807 292 round_to_K(HeapRegionRemSet::static_mem_size()),
tschatzl@5807 293 round_to_K(HeapRegionRemSet::fl_mem_size()));
tschatzl@5807 294
tschatzl@5807 295 out->print_cr(" "SIZE_FORMAT" occupied cards represented.",
tschatzl@5807 296 total_cards_occupied());
tschatzl@5807 297 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
tschatzl@5807 298 (*current)->print_cards_occupied_info_on(out, total_cards_occupied());
tschatzl@5807 299 }
tschatzl@5807 300
tschatzl@5807 301 // Largest sized rem set region statistics
tschatzl@5807 302 HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set();
tschatzl@5807 303 out->print_cr(" Region with largest rem set = "HR_FORMAT", "
tschatzl@5807 304 "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.",
tschatzl@5807 305 HR_FORMAT_PARAMS(max_rs_mem_sz_region()),
tschatzl@5807 306 round_to_K(rem_set->mem_size()),
tschatzl@5807 307 round_to_K(rem_set->occupied()));
tschatzl@5807 308
tschatzl@5807 309 // Strong code root statistics
tschatzl@5807 310 HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set();
tschatzl@5807 311 out->print_cr(" Total heap region code root sets sizes = "SIZE_FORMAT"K."
tschatzl@5807 312 " Max = "SIZE_FORMAT"K.",
tschatzl@5807 313 round_to_K(total_code_root_mem_sz()),
tschatzl@5807 314 round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()));
tschatzl@5807 315 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
tschatzl@5807 316 (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz());
tschatzl@5807 317 }
tschatzl@5807 318
tschatzl@5807 319 out->print_cr(" "SIZE_FORMAT" code roots represented.",
tschatzl@5807 320 total_code_root_elems());
tschatzl@5807 321 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) {
tschatzl@5807 322 (*current)->print_code_root_elems_info_on(out, total_code_root_elems());
tschatzl@5807 323 }
tschatzl@5807 324
tschatzl@5807 325 out->print_cr(" Region with largest amount of code roots = "HR_FORMAT", "
tschatzl@5807 326 "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".",
tschatzl@5807 327 HR_FORMAT_PARAMS(max_code_root_mem_sz_region()),
tschatzl@5807 328 round_to_K(max_code_root_rem_set->strong_code_roots_mem_size()),
tschatzl@5807 329 round_to_K(max_code_root_rem_set->strong_code_roots_list_length()));
tschatzl@5807 330 }
tschatzl@5204 331 };
tschatzl@5204 332
tschatzl@5204 333 void G1RemSetSummary::print_on(outputStream* out) {
tschatzl@5807 334 out->print_cr("\n Recent concurrent refinement statistics");
tschatzl@5807 335 out->print_cr(" Processed "SIZE_FORMAT" cards",
tschatzl@5204 336 num_concurrent_refined_cards());
sjohanss@6009 337 out->print_cr(" Of "SIZE_FORMAT" completed buffers:", num_processed_buf_total());
sjohanss@6009 338 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by concurrent RS threads.",
tschatzl@5204 339 num_processed_buf_total(),
tschatzl@5807 340 percent_of(num_processed_buf_rs_threads(), num_processed_buf_total()));
sjohanss@6009 341 out->print_cr(" "SIZE_FORMAT_W(8)" (%5.1f%%) by mutator threads.",
tschatzl@5204 342 num_processed_buf_mutator(),
tschatzl@5807 343 percent_of(num_processed_buf_mutator(), num_processed_buf_total()));
sjohanss@6009 344 out->print_cr(" Did "SIZE_FORMAT" coarsenings.", num_coarsenings());
tschatzl@5204 345 out->print_cr(" Concurrent RS threads times (s)");
tschatzl@5204 346 out->print(" ");
tschatzl@5204 347 for (uint i = 0; i < _num_vtimes; i++) {
tschatzl@5204 348 out->print(" %5.2f", rs_thread_vtime(i));
tschatzl@5204 349 }
tschatzl@5204 350 out->cr();
tschatzl@5204 351 out->print_cr(" Concurrent sampling threads times (s)");
tschatzl@5204 352 out->print_cr(" %5.2f", sampling_thread_vtime());
tschatzl@5204 353
tschatzl@5204 354 HRRSStatsIter blk;
tschatzl@5204 355 G1CollectedHeap::heap()->heap_region_iterate(&blk);
tschatzl@5807 356 blk.print_summary_on(out);
tschatzl@5204 357 }

mercurial