Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This guide explains dataflow parallelism and how it can improve the execution time of Concrete circuits.
Dataflow parallelism is particularly useful when the circuit performs computations that are neither completely independent (such as loop/doall parallelism) nor fully dependent (e.g. sequential, non-parallelizable code). In such cases dataflow tasks can execute as soon as their inputs are available and thus minimizing over-synchronization.
Without dataflow parallelism, circuit is executed operation by operation, like an imperative language. If the operations themselves are not tensorized, loop parallelism would not be utilized and the entire execution would happen in a single thread. Dataflow parallelism changes this by analyzing the operations and their dependencies within the circuit to determine what can be done in parallel and what cannot. Then it distributes the tasks that can be done in parallel to different threads.
For example:
This prints:
The reason for that is:
To summarize, dataflow analyzes the circuit to determine which parts of the circuit can be run at the same time, and tries to run as many operations as possible in parallel.
When the circuit is tensorized, dataflow might slow execution down since the tensor operations already use multiple threads and adding dataflow on top creates congestion in the CPU between the HPX (dataflow parallelism runtime) and OpenMP (loop parallelism runtime). So try both before deciding on whether to use dataflow or not.
This guide teaches how to improve the execution time of Concrete circuits by using some special operations that reduce the bit width of the input of the table lookup.
There are two extensions which can reduce the bit width of the table lookup input, and , which can improve performance by sacrificing exactness.
For example the following code:
prints:
This guide teaches how to improve the execution time of Concrete circuits by using different conversion strategies for complex operations.
Concrete provides multiple implementation strategies for these complex operations:
The default strategy is the one that doesn't increase the input bit width, even if it's less optimal than the others. If you don't care about the input bit widths (e.g., if the inputs are only used in this operation), you should definitely change the default strategy.
Choosing the correct strategy can lead to big speedups. So if you are not sure which one to use, you can compile with different strategies and compare the complexity.
For example, the following code:
prints:
or:
prints:
As you can see, strategies can affect the performance a lot! So make sure to select the appropriate one for your use case if you want to optimize performance.
This guide explains tensorization and how it can improve the execution time of Concrete circuits.
Tensors should be used instead of scalars when possible to maximize loop parallelism.
For example:
This prints:
Enabling dataflow is kind of letting the runtime do this for you. It'd also help in the specific case.
This guide teaches how costly table lookups are, and how to optimize them to improve the execution time of Concrete circuits.
The most costly operation in Concrete is the table lookup operation, so one of the primary goals of optimizing performance is to reduce the amount of table lookups.
Furthermore, the bit width of the input of the table lookup plays a major role in performance.
The code above prints:
This guide introduces the different options for parallelism in Concrete and how to utilize them to improve the execution time of Concrete circuits.
Modern CPUs have multiple cores to perform computation and utilizing multiple cores is a great way to boost performance.
There are two kinds of parallelism in Concrete:
Loop parallelism to make tensor operations parallel, achieved by using
Dataflow parallelism to make independent operations parallel, achieved by using
Loop parallelism is enabled by default, as it's supported on all platforms. Dataflow parallelism however is only supported on Linux, hence not enabled by default.
This guide explains how to optimize Concrete circuits extensively.
It's split in 3 sections:
: to make circuits utilize more cores.
: to optimize the most expensive operation in Concrete.
: to make Concrete select more performant parameters.
And displays:
This guide teaches how to improve the execution time of Concrete circuits by using bit extraction.
Bit extraction is a cheap way to extract certain bits of encrypted values. It can be very useful for improving the performance of circuits.
For example:
prints:
That's almost 8x improvement to circuit complexity!
This guide explains how setting p_error
configuration option can affect the performance of Concrete circuits.
Adjusting table lookup error probability is discussed extensively in Table lookup exactness section. The idea is to sacrifice exactness to gain performance.
For example:
This prints:
This guide explains how to optimize cryptographic parameters by specifying composition when using modules.
When using modules, make sure to specify composition so that the compiler can select more optimal parameters based on how the functions in the module would be used.
For example:
This prints:
It means that specifying composition resulted in ~35% improvement to complexity for computing cube(square(x))
.
This guide explains how to help Concrete Optimizer to select more performant parameters to improve the execution time of Concrete circuits.
The idea is to obtain more optimal cryptographic parameters (especially for table lookups) without changing the operations within the circuit.
This guide teaches how to improve the execution time of Concrete circuits by reducing the amount of table lookups.
Reducing the amount of table lookups is probably the most complicated guide in this section as it's not automated. The idea is to use mathematical properties of operations to reduce the amount of table lookups needed to achieve the result.
One great example is in adding big integers in bitmap representation. Here is the basic implementation:
There are two table lookups within the loop body, one for >>
and one for %
.
This implementation is not optimal though, since the same output can be achieved with just a single table lookup:
It was possible to do this because the original operations had a mathematical equivalence with the optimized operations and optimized operations achieved the same output with less table lookups!
Here is the full code example and some numbers for this optimization:
prints:
which is almost half the amount of table lookups and ~2x less complexity for the same operation!
This guide teaches how to improve the execution time of Concrete circuits by using approximate mode for rounding.
You can enable approximate mode to gain even more performance when using rounding by sacrificing some more exactness:
prints: