Skip to content
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

[RefC] Object Immortalization and Pre-Generation of Constants #3242

Merged
merged 21 commits into from
Nov 20, 2024

Conversation

seagull-kamome
Copy link
Contributor

Description

This PR immortalizes objects whose reference counter has reached its maximum value and makes them excluded from GC. This immortalization is used to make the following improvements.

  • Since there is no longer any need to worry about the refCounter overflowing to 0, change the refCounter from int to uint16_t to reduce the size of the Value_Header and improve memory usage efficiency.
  • Statically generate constants to reduce runtime cost and share data. Constants are naturally immortal.
    Statically generate values that often appear at runtime, such as empty strings and integers less than 100, and share them at runtime to reduce allocation costs. This heuristic may attract many opinions, but it is a good first-try choice.

On the other hand, there is no way to release immortal objects, so they leak. Dynamic immortalization rarely occurs, but it is a problem for programs that run for long periods of time, such as servers. A secondary GC is needed to solve this, but is not implemented in this PR.

Should this change go in the CHANGELOG?

  • If this is a fix, user-facing change, a compiler change, or a new paper
    implementation, I have updated CHANGELOG_NEXT.md (and potentially also
    CONTRIBUTORS.md).

  * Shrink Value_Header to improve utilization of memory.
  * When refCounter reaches its maximum, the object is immortalized to
    avoid overflow. This immotalization is also used to represent
    statically allocated stock objects.
  * Prepare some commonly seen values and share it to improve memory usage.
  * Added debug code to dump memory stats.
* Commonly seen values such as integers less than 100 are predefined and shared.
* Constant String, Int64, Bits64 and Double values are allocated statically as
  indestructible and shared.
Refactor constantName function to return Core String type
and handle unsupported types by throwing InternalError exception.
@mattpolzin mattpolzin added the backend: refc C with reference counting backend label Apr 1, 2024
Ch x => pure "idris2_mkChar(\{escapeChar x})"
Str _ => orStagen
PrT t => pure $ cPrimType t
_ => pure "NULL"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this catch-all feels a bit brittle to me at first look at least

Copy link
Contributor Author

@seagull-kamome seagull-kamome Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the last commit, I fixed this to improve coverage.

B64 x => pure "((Value*)&idris2_constant_Bits64_\{show x})"
Db x => pure "((Value*)&idris2_constant_Double_\{cCleanString $ show x})"
Str x => pure "((Value*)&idris2_constant_String_\{n})"
_ => throw $ InternalError "[refc] Unsupported type of constant."
Copy link
Collaborator

@mattpolzin mattpolzin Jun 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this compile-time error feels like it could be fairly easily remediated by a new smaller data-type than Constant so that we aren't relying on the invariant that no new type of constant is stored in ConstDef without a new case being added here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed the changes.

I hope I understand the problem correctly. Anyway, this eliminated the runtime error

support/refc/memoryManagement.c Outdated Show resolved Hide resolved
Comment on lines +210 to +214
} else if (elem->header.refCounter != 1) {
--elem->header.refCounter;
return;
} else {
IDRIS2_INC_MEMSTAT(n_freed);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice that whereas elem->header.refCounter used to be decremented prior to freeing, now it is not; that seems theoretically ok to me, but I wanted to make sure it was intentional because I have not verified that nothing downstream of this code would double check the ref count.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided not to write back the 0 value of the counter because I thought the overhead of updating the contents of a deleted object would be wasted.

The improvements are so small that they have little real effect.

@andrevidela
Copy link
Collaborator

@seagull-kamome @mattpolzin any chance we can get this closer to a resolution?

@mattpolzin
Copy link
Collaborator

I had some requests related to the Idris2 code that I’d like to see discussed if not acted upon but overall the LR felt close the last time I looked it over.

@seagull-kamome
Copy link
Contributor Author

I apologize for any inconvenience caused to you due to my poor time control.

I just committed the latest code. I hope this clears up all doubts.

@mattpolzin
Copy link
Collaborator

No apology needed. None of us are making any implicit promises by volunteering our time including you. Thanks for following up. It’s an exceedingly busy time for me with a 3 day old baby but I’ll re-review this when I can ❤️.

Copy link
Collaborator

@mattpolzin mattpolzin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks for another nice bit of machinery in the RefC backend.

@mattpolzin mattpolzin merged commit f016dad into idris-lang:main Nov 20, 2024
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend: refc C with reference counting backend
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants