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

Add a garbage collector to task queue #29

Open
wants to merge 5 commits into
base: stable
Choose a base branch
from
Open

Add a garbage collector to task queue #29

wants to merge 5 commits into from

Conversation

mratsim
Copy link
Contributor

@mratsim mratsim commented Feb 6, 2023

The per-thread task queues grows if it can not fit all pending tasks in queue but never release the extra memory buffer.

In practice it should have no impact on Nimbus, it would require a task to spawna lot of tasks to fill the default queue (32 tasks) and on Nimbus it is only used for parallelizing batch signature verification, which spawns as many tasks as there are cores.

mratsim and others added 2 commits February 6, 2023 16:57
The per-threadtask queues grows if it can not fit all pending tasks in queue but never release the extra memory buffer.

In practice it should have no impact on Nimbus, it would require a task to `spawn`a lot of tasks to fill the default queue (32 tasks) and on Nimbus it is only used for parallelizing batch signature verification, which spawns as many tasks as there are cores.
deque.garbage = buf
# publish globally
deque.buf.store(tmp, moRelaxed)
# publish locally
swap(buf, tmp)

proc garbageCollect(deque: var ChaseLevDeque) {.inline.} =
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
proc garbageCollect(deque: var ChaseLevDeque) {.inline.} =
proc garbageCollect(deque: var ChaseLevDeque) =

there's no difference between inline and not on private functions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually there is, you can access private functions and variables from another module, using templates for example.

I'm not too sure how strong a hint visibility((hidden)) is to the compiler but it's definitely less than C static (only accessible from this module) and static inline.

let tmp = node.prevRetired
c_free(node)
node = tmp
deque.garbage = nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Does garbage need to be Atomic as well?

(Doesn't seem like it's necessary to me, but still worth to double-check intent)

deque.garbage = buf
# publish globally
deque.buf.store(tmp, moRelaxed)
# publish locally
swap(buf, tmp)

proc garbageCollect(deque: var ChaseLevDeque) {.inline.} =
Copy link
Contributor

Choose a reason for hiding this comment

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

In grow, there is a comment referring to garbageUsed, but that garbageUsed doesn't seem to exist. Is there something missing, or should the comment be cleaned up?

@@ -48,9 +48,7 @@ type
## Backend buffer of a ChaseLevDeque
## `capacity` MUST be a power of 2

# Note: update tp_allocUnchecked allocation if any field changes.
Copy link
Contributor

Choose a reason for hiding this comment

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

The tp_allocUnchecked comment still applies, even with the renamed field.

@@ -148,6 +150,10 @@ proc push*[T](deque: var ChaseLevDeque[T], item: T) =
# Full queue
deque.grow(a, t, b)

if not deque.garbage.isNil and b == t:
# Empty queue, no thieves can have a pointer to an old retired buffer
Copy link
Contributor

Choose a reason for hiding this comment

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

Assumption seems correct to me, if steal copies rawBuffer.

If steal were lent instead, the c_free(node) could mess with it, right?

taskpools/chase_lev_deques.nim Outdated Show resolved Hide resolved
# Note: update tp_allocUnchecked allocation if any field changes.
# Unused. There is no memory reclamation scheme.
prev: ptr Buf[T]
prevRetired: ptr Buf[T] # intrusive linked list. Used for garbage collection
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe prevGarbage, or even just garbage to keep nomenclature consistent, instead of using retired and garbage for the same concept.

also not sure about intrusive in comment.

deque.garbage = buf
# publish globally
deque.buf.store(tmp, moRelaxed)
# publish locally
swap(buf, tmp)

proc garbageCollect(deque: var ChaseLevDeque) {.inline.} =
var node = deque.garbage
Copy link
Contributor

Choose a reason for hiding this comment

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

If garbageCollect takes the Buf[T] instead of the ChaseLevDeque, I think the extra garbage in ChaseLevDequeue would no longer be necessary. We could simply start here at buf.prevGarbage instead. garbageCollect is only called when no thieves are present, by the owner, so it should be safe imo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants