Repository navigation
Avoid copying unchanged string pages during collection #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Keep strings across repeated collections, then change some old strings. | ||
| count = Integer(ARGV.fetch(0, '20000')) | ||
| rounds = Integer(ARGV.fetch(1, '20')) | ||
| strings = Array.new(count) { |i| ('x' * 256) + i.to_s } | ||
| GC.start | ||
| start = Process.clock_gettime(Process::CLOCK_MONOTONIC) | ||
| rounds.times { GC.start } | ||
| warn "collections=#{rounds} seconds=#{Process.clock_gettime(Process::CLOCK_MONOTONIC) - start}" | ||
| p strings.each_with_index.all? { |s, i| s == ('x' * 256) + i.to_s } | ||
| strings.each_with_index { |s, i| s.replace("changed#{i}") if i % 499 == 0 } | ||
| GC.start | ||
| p strings.each_with_index.all? { |s, i| s == (i % 499 == 0 ? "changed#{i}" : ('x' * 256) + i.to_s) } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| strings = Array.new(9000) { |i| "value#{i}" } | ||
| empty = Array.new(50) { '' } | ||
| binary = "a\0\xff".b | ||
| held = Fiber.new do | ||
| strings[4096].each_char { |char| Fiber.yield(char) } | ||
| :done | ||
| end | ||
| first = held.resume | ||
| 3.times { GC.start } | ||
| p strings.each_with_index.all? { |s, i| s == "value#{i}" } | ||
| p [empty.all?(&:empty?), binary.bytes] | ||
|
|
||
| # Old pages must become eligible for compaction again after a mutation. | ||
| strings[0].replace('changed') | ||
| strings[4095] << ' appended' | ||
| strings[8192].clear | ||
| binary << "\x80".b | ||
| 3.times { GC.start } | ||
| p [strings[0], strings[4095], strings[8192], binary.bytes] | ||
| rest = '' | ||
| while held.alive? | ||
| char = held.resume | ||
| rest << char unless char == :done | ||
| end | ||
| p first + rest | ||
|
|
||
| # Drop the old values and exercise pages reused by fresh allocations. | ||
| strings = nil | ||
| GC.start | ||
| fresh = Array.new(9000) { |i| i.to_s } | ||
| GC.start | ||
| p fresh.each_with_index.all? { |s, i| s == i.to_s } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #!/usr/bin/env python3 | ||
| """Exercise the production compaction decision against the pinned Vec runtime.""" | ||
| import os | ||
| from pathlib import Path | ||
| import re | ||
| import subprocess | ||
| import tempfile | ||
|
|
||
| ROOT = Path(__file__).resolve().parent.parent | ||
| compiler = os.environ.get('MERE', str(ROOT / '.mere-compiler/_build/default/bin/mere.exe')) | ||
| state = (ROOT / 'm_state.mere').read_text() | ||
| # Compile the actual production helper, rather than duplicating its decision | ||
| # in a C model. The controlled pin exercises both native early-return paths. | ||
| helper = re.search(r'let str_pg_try_compact = fn pg ->.*?;', state, re.S) | ||
| assert helper, 'production compaction helper not found' | ||
| program = ''' | ||
| extern fn test_set_pin: int -> int; | ||
| let pg = vec_new (); | ||
| let _ = vec_push pg "kept"; | ||
| let _ = vec_compact pg; | ||
| let _ = vec_set pg 0 (str_repeat "x" 8388608); | ||
| let _ = vec_set pg 0 "kept"; | ||
| let before = vec_bytes pg; | ||
| let _ = print_bool (before > 8388608); | ||
| let _ = test_set_pin 1; | ||
| // First establish the native baseline; then defer for below-threshold growth. | ||
| let _ = print_bool (not (str_pg_try_compact pg)); | ||
| let _ = print_bool (not (str_pg_try_compact pg)); | ||
|
284km marked this conversation as resolved.
Resolved
|
||
| let _ = print_bool (vec_bytes pg == before); | ||
| let _ = print_bool (vec_get pg 0 == "kept"); | ||
| let _ = test_set_pin 0; | ||
| // No intervening page mutation: the pending work must reclaim old storage. | ||
| let _ = print_bool (str_pg_try_compact pg); | ||
| let _ = print_bool (vec_bytes pg == 4096); | ||
| let _ = print_bool (vec_get pg 0 == "kept"); | ||
| // Equal-capacity copies cannot be distinguished from deferrals; retry safely. | ||
| let _ = print_bool (not (str_pg_try_compact pg)); | ||
| let _ = print_bool (vec_get pg 0 == "kept"); | ||
| ''' | ||
| native = ''' | ||
| static int test_forced_pin(__lang_region *region, int growth) { | ||
| (void)region; (void)growth; | ||
| return 1; | ||
| } | ||
| int test_set_pin(int enabled) { | ||
| __lang_region_pinned = enabled ? test_forced_pin : 0; | ||
| return 0; | ||
| } | ||
| ''' | ||
| with tempfile.TemporaryDirectory(prefix='mere-string-page-') as directory: | ||
| path = Path(directory) | ||
| source = path / 'check.mere' | ||
| source.write_text(helper[0] + '\n' + program) | ||
| emitted = subprocess.run([compiler, '-c', str(source)], capture_output=True, | ||
| check=True, timeout=60).stdout | ||
| cfile = path / 'check.c' | ||
| cfile.write_bytes(emitted + native.encode()) | ||
| binary = path / 'check' | ||
| subprocess.run(['clang', '-O2', '-w', '-fbracket-depth=1024', str(cfile), | ||
| '-lm', '-o', str(binary)], check=True, timeout=60) | ||
| result = subprocess.run([str(binary)], capture_output=True, check=True, timeout=20) | ||
| assert result.stdout == b'true\n' * 10, result.stdout | ||
| print('String page compaction: deferred pins retry and reclaim without another write') | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.