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

fix: check thread-safe-region feature(post-split) #296

Merged
merged 10 commits into from
Mar 28, 2024

Conversation

duguorong009
Copy link

@duguorong009 duguorong009 commented Mar 11, 2024

Description

  • check & re-enable the temporary-disabled thread-safe-region feature usage across the crates

Related issues

Changes

  • remove the thread-safe-region feature & related code for halo2_backend::plonk::keygen::Assembly struct
  • remove the thread-safe-region-related code in MockProver(halo2_frontend::dev)
  • derive the Ord, PartialOrd for halo2_middleware::circuit::Cell struct
  • add the sorting of permutation copies in compile_circuit(halo2_frontend) process

Copy link

@davidnevadoc davidnevadoc left a comment

Choose a reason for hiding this comment

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

Even though the note in the code says that the thread-safe feature should be moved to the frontend, it must be kept in both front and back because in the front is needed for the assigning regions in parallel, and in the back it is needed for the assambly keyen. Is this right?

@duguorong009
Copy link
Author

Even though the note in the code says that the thread-safe feature should be moved to the frontend, it must be kept in both front and back because in the front is needed for the assigning regions in parallel, and in the back it is needed for the assambly keyen. Is this right?

Yes, you are right. @davidnevadoc
#258 (comment)

@ed255
Copy link
Member

ed255 commented Mar 12, 2024

I want to discuss this feature.

For context:

  • Before the frontend-backend split, the way copy constrains worked is that for every copy constraint you include (by specifying 2 cells), the permutation::Assembly keeps growing a structure that holds the cycles (and they are updated in place). The order of elements in the cycle depend on the order of including the copy constraints, and this affects the setup keys.
    • This means that if you try to do assignment in parallel where you include copy constraints in parallel, the order of the copy constraints is not deterministic, and thus the cycles are not deterministic. Nevertheless this couldn't be done because Region was not Send + Sync, so you couldn't access a Region from different threads; and you need a Region to include a copy constraint.
  • In feat: send sync region #180 we got the feature thread-safe-region. On one hand this makes the Region: Send + Sync, which allows it to be shared across different threads. But then the order of the copy constraints is not deterministic. For that reason, that PR also includes a new implementation of permutation::Assembly that regenerates the cycles before keygen such that the cycles are always deterministic (no matter the original order).
  • With the frontend-backend split, the cycle generation only appears in the backend. Now the frontend just keeps a list of pairs of cells. Then in keygen, the backend receives this list, and builds the cycles in a single step:
    pub(crate) fn new_from_assembly_mid(
    n: usize,
    p: &ArgumentV2,
    a: &AssemblyMid,
    ) -> Result<Self, Error> {
    let mut assembly = Self::new(n, &p.clone().into());
    for copy in &a.copies {
    assembly.copy(copy.0.column, copy.0.row, copy.1.column, copy.1.row)?;
    }
    Ok(assembly)
    }

So, while I think the current PR is correct and brings back the thread-safe-region (which I agree, needs to be in the frontend to have thread-safe Region, and in the backend to have deterministic permutation keygen); I believe that with the current frontend-backend split there's a much easier way to achieve the same:
Before this step:

for copy in &a.copies {
assembly.copy(copy.0.column, copy.0.row, copy.1.column, copy.1.row)?;
}

Sort a.copies.

And with that we would have the same outcome without the need of two implementations of permutation::Assembly.

What do you think about this?

There's an extra thing that we can look into: since now the cycles are generated in one pass (instead of being updated in-place), maybe we can find a simpler implementation for that.

@duguorong009
Copy link
Author

Thanks for detailed comment! @ed255
I think you are right.
We can make this PR better.

I think we should come back to this PR after #290 is completed.
Then, we can discuss the feature in cleaner codebase.

@duguorong009 duguorong009 marked this pull request as draft March 13, 2024 03:46
@duguorong009 duguorong009 force-pushed the gr@post-split-check-thread-safe-region branch from d822aff to 670d620 Compare March 18, 2024 15:37
@duguorong009 duguorong009 marked this pull request as ready for review March 27, 2024 02:08
Copy link
Member

@CPerezz CPerezz left a comment

Choose a reason for hiding this comment

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

I'm confused. The PR says it enables the feature but the actual PR removes the feature.
If we want to actually remove it (which I don't think we should (without discussing first)), we should also remove the docs about it that we have in Readme and MDBook.

Copy link
Member

@ed255 ed255 left a comment

Choose a reason for hiding this comment

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

There's one question that comes to my mind: should we add #[cfg(feature = "thread-safe-region")] before sorting the copies?

Without that feature, the regions are not thread safe so the copies should always be stable; so technically the sorting is only needed when the tread-safe-region feature is enabled. If we add the line before sorting, we'll skip sorting when it's not needed, which may reduce the overhead?

Now this only makes sense if the overhead of the sorting is significant, but I don't know how significant it is.

halo2_frontend/src/dev.rs Show resolved Hide resolved
@ed255
Copy link
Member

ed255 commented Mar 27, 2024

I'm confused. The PR says it enables the feature but the actual PR removes the feature. If we want to actually remove it (which I don't think we should (without discussing first)), we should also remove the docs about it that we have in Readme and MDBook.

The approach that the PR implements has changed since it was opened. In particular, since we now hold all the copies in a vector instead of building the cycles incrementally, we don't need a stable incremental cycle generation algorithm, because we can just sort the entries in the copies. For this reason the backend doesn't need the thread safe feature, only the frontend (which is where the Region exists).

So this PR is not removing any "capability".

@duguorong009
Copy link
Author

There's one question that comes to my mind: should we add #[cfg(feature = "thread-safe-region")] before sorting the copies?

Without that feature, the regions are not thread safe so the copies should always be stable; so technically the sorting is only needed when the tread-safe-region feature is enabled. If we add the line before sorting, we'll skip sorting when it's not needed, which may reduce the overhead?

Now this only makes sense if the overhead of the sorting is significant, but I don't know how significant it is.

I think it is better to add the thread-safe-region feature before sorting the copies.
Sorting idea started from this thread-safe-region feature.
Hence, I believe it makes sense to add feature.
Also, I think the overhead of sorting vector is costly, even in small circuits.

@ed255
Copy link
Member

ed255 commented Mar 27, 2024

There's one question that comes to my mind: should we add #[cfg(feature = "thread-safe-region")] before sorting the copies?
Without that feature, the regions are not thread safe so the copies should always be stable; so technically the sorting is only needed when the tread-safe-region feature is enabled. If we add the line before sorting, we'll skip sorting when it's not needed, which may reduce the overhead?
Now this only makes sense if the overhead of the sorting is significant, but I don't know how significant it is.

I think it is better to add the thread-safe-region feature before sorting the copies. Sorting idea started from this thread-safe-region feature. Hence, I believe it makes sense to add feature. Also, I think the overhead of sorting vector is costly, even in small circuits.

Sounds good, I think this is the safest option :)

@duguorong009 duguorong009 changed the title fix: enable thread-safe-region feature(post-split) fix: check thread-safe-region feature(post-split) Mar 27, 2024
@duguorong009 duguorong009 requested review from CPerezz and ed255 March 27, 2024 14:39
Copy link
Member

@ed255 ed255 left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Member

@CPerezz CPerezz left a comment

Choose a reason for hiding this comment

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

Thanks for the explanations! LGTM!

@duguorong009 duguorong009 merged commit 62bf22c into main Mar 28, 2024
15 checks passed
@duguorong009 duguorong009 deleted the gr@post-split-check-thread-safe-region branch March 28, 2024 07:38
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.

[post frontend-backend split] Bring back thread-safe-region permutation Assembly
4 participants