diff options
Diffstat (limited to '036refcount.cc')
-rw-r--r-- | 036refcount.cc | 554 |
1 files changed, 2 insertions, 552 deletions
diff --git a/036refcount.cc b/036refcount.cc index 418e22b0..f9668be4 100644 --- a/036refcount.cc +++ b/036refcount.cc @@ -1,218 +1,9 @@ -//: Update refcounts when copying addresses. -//: The top of the address layer has more on refcounts. - -:(scenario refcounts) -def main [ - 1:address:num <- copy 1000/unsafe - 2:address:num <- copy 1:address:num - 1:address:num <- copy 0 - 2:address:num <- copy 0 -] -+run: {1: ("address" "number")} <- copy {1000: "literal", "unsafe": ()} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: ("address" "number")} <- copy {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {1: ("address" "number")} <- copy {0: "literal"} -+mem: decrementing refcount of 1000: 2 -> 1 -+run: {2: ("address" "number")} <- copy {0: "literal"} -+mem: decrementing refcount of 1000: 1 -> 0 - -:(after "Writing Instruction Product(i)") -if (is_primitive(current_instruction().operation)) { - reagent/*copy*/ tmp = current_instruction().products.at(i); - canonize(tmp); - update_any_refcounts(tmp, products.at(i)); -} - -:(before "End Globals") -bool Reclaim_memory = true; -:(before "End Commandline Options(*arg)") -else if (is_equal(*arg, "--no-reclaim")) { - cerr << "Disabling memory reclamation. Some tests will fail.\n"; - Reclaim_memory = false; -} -:(code) -void update_any_refcounts(const reagent& canonized_x, const vector<double>& data) { - if (!Reclaim_memory) return; - increment_any_refcounts(canonized_x, data); // increment first so we don't reclaim on x <- copy x - decrement_any_refcounts(canonized_x); -} - -void increment_any_refcounts(const reagent& canonized_x, const vector<double>& data) { - if (is_mu_address(canonized_x)) { - assert(scalar(data)); - assert(!canonized_x.metadata.size); - increment_refcount(data.at(0)); - } - // End Increment Refcounts(canonized_x) -} - -void increment_refcount(int new_address) { - assert(new_address >= 0); - if (new_address == 0) return; - ++Total_refcount_updates; - int new_refcount = get_or_insert(Memory, new_address); - trace("mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end(); - put(Memory, new_address, new_refcount+1); -} - -void decrement_any_refcounts(const reagent& canonized_x) { - // Begin Decrement Refcounts(canonized_x) - if (is_mu_address(canonized_x) && canonized_x.value != 0) { - assert(!canonized_x.metadata.size); - decrement_refcount(get_or_insert(Memory, canonized_x.value), payload_type(canonized_x.type), payload_size(canonized_x)); - } - // End Decrement Refcounts(canonized_x) -} - -void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) { - assert(old_address >= 0); - if (old_address == 0) return; - ++Total_refcount_updates; - int old_refcount = get_or_insert(Memory, old_address); - trace("mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end(); - --old_refcount; - put(Memory, old_address, old_refcount); - if (old_refcount < 0) { - cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n'; - if (Trace_stream) Trace_stream->dump(); - exit(1); - } - // End Decrement Refcount(old_address, payload_type, payload_size) -} - int payload_size(reagent/*copy*/ x) { x.properties.push_back(pair<string, string_tree*>("lookup", NULL)); lookup_memory_core(x, /*check_for_null*/false); - return size_of(x) + /*refcount*/1; + return size_of(x); } -:(scenario refcounts_reflexive) -def main [ - 1:address:num <- new number:type - # idempotent copies leave refcount unchanged - 1:address:num <- copy 1:address:num -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {1: ("address" "number")} <- copy {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+mem: decrementing refcount of 1000: 2 -> 1 - -:(scenario refcounts_call) -def main [ - 1:address:num <- new number:type - # passing in addresses to recipes increments refcount - foo 1:address:num - # return does NOT yet decrement refcount; memory must be explicitly managed - 1:address:num <- new number:type -] -def foo [ - 2:address:num <- next-ingredient -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: foo {1: ("address" "number")} -# leave ambiguous precisely when the next increment happens -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: decrementing refcount of 1000: 2 -> 1 - -//: fix up any instructions that don't follow the usual flow of read_memory -//: before the RUN switch, and write_memory after - -:(scenario refcounts_put) -container foo [ - x:address:num -] -def main [ - 1:address:num <- new number:type - 2:address:foo <- new foo:type - *2:address:foo <- put *2:address:foo, x:offset, 1:address:num -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: ("address" "foo")} <- new {foo: "type"} -+mem: incrementing refcount of 1002: 0 -> 1 -+run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} -# put increments refcount -+mem: incrementing refcount of 1000: 1 -> 2 - -:(after "Write Memory in PUT in Run") -reagent/*copy*/ element = element_type(base.type, offset); -assert(!has_property(element, "lookup")); -element.set_value(address); -update_any_refcounts(element, ingredients.at(2)); - -:(scenario refcounts_put_index) -def main [ - 1:address:num <- new number:type - 2:address:array:address:num <- new {(address number): type}, 3 - *2:address:array:address:num <- put-index *2:address:array:address:num, 0, 1:address:num -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"} -+mem: incrementing refcount of 1002: 0 -> 1 -+run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")} -# put-index increments refcount -+mem: incrementing refcount of 1000: 1 -> 2 - -:(after "Write Memory in PUT_INDEX in Run") -reagent/*local*/ element; -element.set_value(address); -element.type = copy_array_element(base.type); -update_any_refcounts(element, value); - -:(scenario refcounts_maybe_convert) -exclusive-container foo [ - x:num - p:address:num -] -def main [ - 1:address:num <- new number:type - 2:foo <- merge 1/p, 1:address:num - 4:address:num, 5:bool <- maybe-convert 2:foo, 1:variant/p -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -# merging in an address increments refcount -+run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()} -# maybe-convert increments refcount on success -+mem: incrementing refcount of 1000: 2 -> 3 - -:(after "Write Memory in Successful MAYBE_CONVERT") -// todo: double-check data here as well -vector<double> data; -for (int i = 0; i < size_of(product); ++i) - data.push_back(get_or_insert(Memory, base_address+/*skip tag*/1+i)); -update_any_refcounts(product, data); - -//:: manage refcounts in instructions that copy multiple locations at a time - -:(scenario refcounts_copy_nested) -container foo [ - x:address:num # address inside container -] -def main [ - 1:address:num <- new number:type - 2:address:foo <- new foo:type - *2:address:foo <- put *2:address:foo, x:offset, 1:address:num - 3:foo <- copy *2:address:foo -] -+transform: compute address offsets for container foo -+transform: checking container foo, element 0 -+transform: address at offset 0 -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -# copying a container increments refcounts of any contained addresses -+run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()} -+mem: incrementing refcount of 1000: 2 -> 3 - :(before "End type_tree Definition") struct address_element_info { // Where inside a container type (after flattening nested containers!) the @@ -268,7 +59,7 @@ struct tag_condition_info { // // IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN // for all address_element_infos: -// you need to update refcounts for the address at offset pointing to a payload of type payload_type (just in case we need to abandon something in the process) +// there is an address at 'offset' pointing to a payload of type payload_type map<set<tag_condition_info>, set<address_element_info> > address; :(code) bool operator<(const set<tag_condition_info>& a, const set<tag_condition_info>& b) { @@ -699,40 +490,6 @@ void test_container_address_offsets_from_repeated_address_and_array_types() { CHECK_EQ(address_offsets2.begin()->payload_type->name, "number"); } -//: use metadata.address to update refcounts within containers, arrays and -//: exclusive containers - -:(before "End Increment Refcounts(canonized_x)") -if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - const container_metadata& metadata = get(Container_metadata, canonized_x.type); - for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - if (!all_match(data, p->first)) continue; - for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) - increment_refcount(data.at(info->offset)); - } -} - -:(before "End Decrement Refcounts(canonized_x)") -if (is_mu_container(canonized_x) || is_mu_exclusive_container(canonized_x)) { - trace("mem") << "need to read old value of '" << to_string(canonized_x) << "' to figure out what refcounts to decrement" << end(); - // read from canonized_x but without canonizing again - reagent/*copy*/ tmp = canonized_x; - tmp.properties.push_back(pair<string, string_tree*>("raw", NULL)); - vector<double> data = read_memory(tmp); - trace("mem") << "done reading old value of '" << to_string(canonized_x) << "'" << end(); - const container_metadata& metadata = get(Container_metadata, canonized_x.type); - for (map<set<tag_condition_info>, set<address_element_info> >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { - if (!all_match(data, p->first)) continue; - for (set<address_element_info>::const_iterator info = p->second.begin(); info != p->second.end(); ++info) { - int element_address = get_or_insert(Memory, canonized_x.value + info->offset); - reagent/*local*/ element; - element.set_value(element_address+/*skip refcount*/1); - element.type = new type_tree(*info->payload_type); - decrement_refcount(element_address, info->payload_type, size_of(element)+/*refcount*/1); - } - } -} - :(code) bool all_match(const vector<double>& data, const set<tag_condition_info>& conditions) { for (set<tag_condition_info>::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { @@ -742,271 +499,6 @@ bool all_match(const vector<double>& data, const set<tag_condition_info>& condit return true; } -:(scenario refcounts_put_container) -container foo [ - a:bar # contains an address -] -container bar [ - x:address:num -] -def main [ - 1:address:num <- new number:type - 2:bar <- merge 1:address:num - 3:address:foo <- new foo:type - *3:address:foo <- put *3:address:foo, a:offset, 2:bar -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: "bar"} <- merge {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} -# put increments refcount inside container -+mem: incrementing refcount of 1000: 2 -> 3 - -:(scenario refcounts_put_index_array) -container bar [ - x:address:num -] -def main [ - 1:address:num <- new number:type - 2:bar <- merge 1:address:num - 3:address:array:bar <- new bar:type, 3 - *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: "bar"} <- merge {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} -# put-index increments refcount inside container -+mem: incrementing refcount of 1000: 2 -> 3 - -:(scenario refcounts_maybe_convert_container) -exclusive-container foo [ - a:num - b:bar # contains an address -] -container bar [ - x:address:num -] -def main [ - 1:address:num <- new number:type - 2:bar <- merge 1:address:num - 3:foo <- merge 1/b, 2:bar - 5:bar, 6:bool <- maybe-convert 3:foo, 1:variant/b -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: "bar"} <- merge {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} -+mem: incrementing refcount of 1000: 2 -> 3 -+run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} -+mem: incrementing refcount of 1000: 3 -> 4 - -:(scenario refcounts_copy_doubly_nested) -container foo [ - a:bar # no addresses - b:curr # contains addresses -] -container bar [ - x:num - y:num -] -container curr [ - x:num - y:address:num # address inside container inside container -] -def main [ - 1:address:num <- new number:type - 2:address:curr <- new curr:type - *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:num - 3:address:foo <- new foo:type - *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr - 4:foo <- copy *3:address:foo -] -+transform: compute address offsets for container foo -+transform: checking container foo, element 1 -+transform: address at offset 3 -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -# storing an address in a container updates its refcount -+run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -# storing a container in a container updates refcounts of any contained addresses -+run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} -+mem: incrementing refcount of 1000: 2 -> 3 -# copying a container containing a container containing an address updates refcount -+run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} -+mem: incrementing refcount of 1000: 3 -> 4 - -:(scenario refcounts_copy_exclusive_container_within_container) -container foo [ - a:num - b:bar -] -exclusive-container bar [ - x:num - y:num - z:address:num -] -def main [ - 1:address:num <- new number:type - 2:bar <- merge 0/x, 34 - 3:foo <- merge 12, 2:bar - 5:bar <- merge 1/y, 35 - 6:foo <- merge 13, 5:bar - 8:bar <- merge 2/z, 1:address:num - 9:foo <- merge 14, 8:bar - 11:foo <- copy 9:foo -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -# no change while merging items of other types -+run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} -+mem: incrementing refcount of 1000: 2 -> 3 -+run: {11: "foo"} <- copy {9: "foo"} -+mem: incrementing refcount of 1000: 3 -> 4 - -:(scenario refcounts_copy_container_within_exclusive_container) -exclusive-container foo [ - a:num - b:bar -] -container bar [ - x:num - y:num - z:address:num -] -def main [ - 1:address:num <- new number:type - 2:foo <- merge 0/a, 34 - 6:foo <- merge 0/a, 35 - 10:bar <- merge 2/x, 15/y, 1:address:num - 13:foo <- merge 1/b, 10:bar - 17:foo <- copy 13:foo -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -# no change while merging items of other types -+run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} -+mem: incrementing refcount of 1000: 2 -> 3 -+run: {17: "foo"} <- copy {13: "foo"} -+mem: incrementing refcount of 1000: 3 -> 4 - -:(scenario refcounts_copy_exclusive_container_within_exclusive_container) -exclusive-container foo [ - a:num - b:bar -] -exclusive-container bar [ - x:num - y:address:num -] -def main [ - 1:address:num <- new number:type - 10:foo <- merge 1/b, 1/y, 1:address:num - 20:foo <- copy 10:foo -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -# no change while merging items of other types -+run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {20: "foo"} <- copy {10: "foo"} -+mem: incrementing refcount of 1000: 2 -> 3 - -:(scenario refcounts_copy_array_within_container) -container foo [ - x:address:array:num -] -def main [ - 1:address:array:num <- new number:type, 3 - 2:foo <- merge 1:address:array:num - 3:address:array:num <- new number:type, 5 - 2:foo <- merge 3:address:array:num -] -+run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: "foo"} <- merge {1: ("address" "array" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: {2: "foo"} <- merge {3: ("address" "array" "number")} -+mem: decrementing refcount of 1000: 2 -> 1 - -:(scenario refcounts_copy_address_within_static_array_within_container) -container foo [ - a:array:bar:3 - b:address:num -] -container bar [ - y:num - z:address:num -] -def main [ - 1:address:num <- new number:type - 2:bar <- merge 34, 1:address:num - 10:array:bar:3 <- create-array - put-index 10:array:bar:3, 1, 2:bar - 20:foo <- merge 10:array:bar:3, 1:address:num - 1:address:num <- copy 0 - 2:bar <- merge 34, 1:address:num - put-index 10:array:bar:3, 1, 2:bar - 20:foo <- merge 10:array:bar:3, 1:address:num -] -+run: {1: ("address" "number")} <- new {number: "type"} -+mem: incrementing refcount of 1000: 0 -> 1 -+run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 1 -> 2 -+run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} -+mem: incrementing refcount of 1000: 2 -> 3 -+run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} -+mem: incrementing refcount of 1000: 3 -> 4 -+mem: incrementing refcount of 1000: 4 -> 5 -+run: {1: ("address" "number")} <- copy {0: "literal"} -+mem: decrementing refcount of 1000: 5 -> 4 -+run: {2: "bar"} <- merge {34: "literal"}, {1: ("address" "number")} -+mem: decrementing refcount of 1000: 4 -> 3 -+run: put-index {10: ("array" "bar" "3")}, {1: "literal"}, {2: "bar"} -+mem: decrementing refcount of 1000: 3 -> 2 -+run: {20: "foo"} <- merge {10: ("array" "bar" "3")}, {1: ("address" "number")} -+mem: decrementing refcount of 1000: 2 -> 1 -+mem: decrementing refcount of 1000: 1 -> 0 - -:(scenario refcounts_handle_exclusive_containers_with_different_tags) -container foo1 [ - x:address:num - y:num -] -container foo2 [ - x:num - y:address:num -] -exclusive-container bar [ - a:foo1 - b:foo2 -] -def main [ - 1:address:num <- copy 12000/unsafe # pretend allocation - *1:address:num <- copy 34 - 2:bar <- merge 0/foo1, 1:address:num, 97 - 5:address:num <- copy 13000/unsafe # pretend allocation - *5:address:num <- copy 35 - 6:bar <- merge 1/foo2, 98, 5:address:num - 2:bar <- copy 6:bar -] -+run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} -+mem: incrementing refcount of 12000: 1 -> 2 -+run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} -+mem: incrementing refcount of 13000: 1 -> 2 -+run: {2: "bar"} <- copy {6: "bar"} -+mem: incrementing refcount of 13000: 2 -> 3 -+mem: decrementing refcount of 12000: 2 -> 1 - -:(code) bool is_mu_container(const reagent& r) { return is_mu_container(r.type); } @@ -1030,45 +522,3 @@ bool is_mu_exclusive_container(const type_tree* type) { type_info& info = get(Type, type->value); return info.kind == EXCLUSIVE_CONTAINER; } - -//:: Counters for trying to understand where Mu programs are spending time -//:: updating refcounts. - -:(before "End Globals") -int Total_refcount_updates = 0; -map<recipe_ordinal, map</*step index*/int, /*num refcount updates*/int> > Num_refcount_updates; -:(after "Running One Instruction") -int initial_num_refcount_updates = Total_refcount_updates; -:(before "End Running One Instruction") -if (Run_profiler) { - Num_refcount_updates[current_call().running_recipe][current_call().running_step_index] - += (Total_refcount_updates - initial_num_refcount_updates); - initial_num_refcount_updates = Total_refcount_updates; -} -:(before "End Non-primitive Call(caller_frame)") -if (Run_profiler) { - Num_refcount_updates[caller_frame.running_recipe][caller_frame.running_step_index] - += (Total_refcount_updates - initial_num_refcount_updates); - initial_num_refcount_updates = Total_refcount_updates; -} -:(after "Begin Return") -if (Run_profiler) { - Num_refcount_updates[current_call().running_recipe][current_call().running_step_index] - += (Total_refcount_updates - initial_num_refcount_updates); - initial_num_refcount_updates = Total_refcount_updates; -} -:(before "End dump_profile") -fout.open("profile.refcounts"); -if (fout) { - for (map<recipe_ordinal, recipe>::iterator p = Recipe.begin(); p != Recipe.end(); ++p) - dump_recipe_profile(p->first, p->second, fout); -} -fout.close(); -:(code) -void dump_recipe_profile(recipe_ordinal ridx, const recipe& r, ostream& out) { - out << "recipe " << r.name << " [\n"; - for (int i = 0; i < SIZE(r.steps); ++i) { - out << std::setw(6) << Num_refcount_updates[ridx][i] << ' ' << to_string(r.steps.at(i)) << '\n'; - } - out << "]\n\n"; -} |