Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/emscripten.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Emscripten

# Builds with emcc and runs the WASM unit tests under node. Guards against
# re-introducing the cache-leak class that issue #249 tracked.

on:
pull_request:
branches: [dev]
push:
branches: [dev, main]
workflow_dispatch:

jobs:
build-and-test:
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with: { node-version: '20' }

- name: Cache emsdk
id: cache-emsdk
uses: actions/cache@v4
with:
path: ~/emsdk
key: emsdk-3.1.59

- name: Install emsdk
if: steps.cache-emsdk.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch 3.1.59 https://github.com/emscripten-core/emsdk.git ~/emsdk
~/emsdk/emsdk install 3.1.59
~/emsdk/emsdk activate 3.1.59

- name: Configure
run: |
source ~/emsdk/emsdk_env.sh
emcmake cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release -DBUILD_UNITTESTS=ON \
-DBUILD_BENCHMARKS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_EXTRAS=OFF \
-DBUILD_STATIC=ON -DBUILD_SHARED=OFF -DWITH_OPENMP=OFF -DNATIVE_SIZE=64 \
-DCMAKE_EXE_LINKER_FLAGS="-s INITIAL_MEMORY=536870912 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4294967296 -s WASM=1 -s NODERAWFS=1 -s STACK_SIZE=5MB -s ASSERTIONS=0"

- name: Build
run: |
source ~/emsdk/emsdk_env.sh
cmake --build build --target core_tests pke_tests -j2

- name: core_tests
working-directory: build/unittest
run: node --max-old-space-size=8192 ./core_tests.js --gtest_color=no

# Split pke_tests across two processes — each stays well below the 4 GB WASM cap.
- name: pke_tests (CKKS + general)
working-directory: build/unittest
run: node --max-old-space-size=8192 ./pke_tests.js --gtest_filter='UTCKKSRNS*:UTCKKSCacheClear*:UTGENERAL*' --gtest_color=no

- name: pke_tests (BFV + BGV + binfhe)
working-directory: build/unittest
run: node --max-old-space-size=8192 ./pke_tests.js --gtest_filter='UTBFV*:UTBGV*:UTBINFHE*' --gtest_color=no
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ option(WITH_BE2 "Include MATHBACKEND 2 in build by setting WITH_BE2 to ON"
option(WITH_BE4 "Include MATHBACKEND 4 in build by setting WITH_BE4 to ON" OFF )
option(WITH_NTL "Include MATHBACKEND 6 and NTL in build by setting WITH_NTL to ON" OFF )
option(WITH_TCM "Activate tcmalloc by setting WITH_TCM to ON" OFF )
option(WITH_MALLOC_TUNING "Tune glibc malloc to retain freed memory for reuse" ON )
option(WITH_NATIVEOPT "Use machine-specific optimizations" OFF )
option(WITH_COVTEST "Turn on to enable coverage testing (can be used with g++ only)" OFF )
option(WITH_NOISE_DEBUG "Use only when running lattice estimator; not for production" OFF )
Expand Down Expand Up @@ -115,6 +116,7 @@ message(STATUS "WITH_BE2: ${WITH_BE2}")
message(STATUS "WITH_BE4: ${WITH_BE4}")
message(STATUS "WITH_NTL: ${WITH_NTL}")
message(STATUS "WITH_TCM: ${WITH_TCM}")
message(STATUS "WITH_MALLOC_TUNING: ${WITH_MALLOC_TUNING}")
message(STATUS "WITH_OPENMP: ${WITH_OPENMP}")
message(STATUS "NATIVE_SIZE: ${NATIVE_SIZE}")
message(STATUS "CKKS_M_FACTOR: ${CKKS_M_FACTOR}")
Expand Down
1 change: 1 addition & 0 deletions configure/config_core.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#cmakedefine WITH_REDUCED_NOISE
#cmakedefine WITH_NTL
#cmakedefine WITH_TCM
#cmakedefine WITH_MALLOC_TUNING
#cmakedefine WITH_OPENMP
#cmakedefine WITH_NATIVEOPT

Expand Down
44 changes: 25 additions & 19 deletions docs/sphinx_rsts/intro/installation/cmake_in_openfhe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,34 @@ Each of the options is enabled by saying ``-DOPTION_NAME=ON`` and is disabled by

The table below shows the current list of options, definition for the option, and a default value.

================== ===================================================================================================================================================================== ==========
OPTION_NAME Description Default
================== ===================================================================================================================================================================== ==========
BUILD_UNITTESTS Set to ON to build unit tests for the library ON
BUILD_EXAMPLES Set to ON to build examples for the library ON
BUILD_BENCHMARKS Set to ON to build benchmarks for the library ON
BUILD_EXTRAS Set to ON to build extra examples for the library OFF
BUILD_SHARED Set to ON to include shared versions of the library ON
BUILD_STATIC Set to ON to include static versions of the library OFF
WITH_BE2 Include Backend 2 in build by setting WITH_BE2 to ON ON
WITH_BE4 Include Backend 4 in build by setting WITH_BE4 to ON ON
WITH_NTL Include Backend 6 and NTL in build by setting WITH_NTL to ON OFF
WITH_TCM Activate tcmalloc by setting WITH_TCM to ON OFF
WITH_OPENMP Use OpenMP to enable <omp.h> ON
WITH_NATIVEOPT Use machine-specific optimizations (major speedup for clang) OFF
NATIVE_SIZE Set default word size for native integer arithmetic to 64 or 128 bits 64
CKKS_M_FACTOR Parameter used to strengthen the CKKS adversarial model in scenarios where decryption results are shared among multiple parties (See Security.md for more details) 1
================== ===================================================================================================================================================================== ==========
==================== ===================================================================================================================================================================== ==========
OPTION_NAME Description Default
==================== ===================================================================================================================================================================== ==========
BUILD_UNITTESTS Set to ON to build unit tests for the library ON
BUILD_EXAMPLES Set to ON to build examples for the library ON
BUILD_BENCHMARKS Set to ON to build benchmarks for the library ON
BUILD_EXTRAS Set to ON to build extra examples for the library OFF
BUILD_SHARED Set to ON to include shared versions of the library ON
BUILD_STATIC Set to ON to include static versions of the library OFF
GIT_SUBMOD_AUTO Automatically update git submodules at CMake configure time ON
WITH_BE2 Include Backend 2 in build by setting WITH_BE2 to ON OFF
WITH_BE4 Include Backend 4 in build by setting WITH_BE4 to ON (always ON when MATHBACKEND=4, the default) ON
WITH_NTL Include Backend 6 and NTL in build by setting WITH_NTL to ON OFF
WITH_TCM Activate tcmalloc by setting WITH_TCM to ON OFF
WITH_MALLOC_TUNING Tune glibc malloc to retain freed memory for reuse (higher performance, higher resident memory; see AllocTrim()) ON
WITH_OPENMP Use OpenMP to enable <omp.h> ON
WITH_NATIVEOPT Use machine-specific optimizations (major speedup for clang) OFF
WITH_COVTEST Turn on to enable coverage testing (can be used with g++ only) OFF
WITH_NOISE_DEBUG Use only when running the lattice estimator; not for production OFF
WITH_REDUCED_NOISE Enable reduced noise within HKS and BFV HPSPOVERQ modes OFF
USE_MACPORTS Use MacPorts installed packages (macOS) OFF
NATIVE_SIZE Set default word size for native integer arithmetic to 64 or 128 bits 64
CKKS_M_FACTOR Parameter used to strengthen the CKKS adversarial model in scenarios where decryption results are shared among multiple parties (See Security.md for more details) 1
==================== ===================================================================================================================================================================== ==========

.. note:: More Options will be added as development progresses

The default math backend for the OpenFHE build is Backend 2 (basic fixed-maximum-length big integers). This default can be changed on the CMake command line by setting the MATHBACKEND variable. For example, to select backend 6 (high performance fixed integers based on the GMP and NTL libraries), use ``-DMATHBACKEND=6`` on the CMake command line.
The default math backend for the OpenFHE build is Backend 4 (dynamically-sized big integers). This default can be changed on the CMake command line by setting the MATHBACKEND variable. For example, to select backend 6 (high performance fixed integers based on the GMP and NTL libraries), use ``-DMATHBACKEND=6`` on the CMake command line.

Detecting Local Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
54 changes: 41 additions & 13 deletions src/core/lib/utils/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,50 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//==================================================================================

#include "config_core.h"
#include "utils/memory.h"

#if defined(__GLIBC__)
#if defined(__APPLE__)
#include <malloc/malloc.h>
#elif defined(__GLIBC__)
#include <malloc.h>
#elif defined(_MSC_VER)
#include <malloc.h>
#endif

namespace lbcrypto {

#if defined(__GLIBC__)
// Tune glibc malloc for FHE allocation patterns. Each homomorphic operation allocates and
// frees many large (~0.5-30 MB) polynomial coefficient buffers. By default glibc returns
// these freed buffers to the OS (brk heap-trim / munmap) and re-faults the pages on the next
// operation; under a single thread this page-fault / kernel-time overhead can dominate
// runtime. Keeping large allocations on the heap (M_MMAP_MAX=0) and never trimming it back to
// the OS (M_TRIM_THRESHOLD=-1) lets the buffers be reused, eliminating the churn. Runs once,
// process-wide, at library load. NOTE: this retains freed memory in-process, so workloads
// with large transient allocation peaks will show a higher resident set size. Use AllocTrim()
// after large allocations are freed if this becomes an issue.
#if defined(WITH_MALLOC_TUNING)
// Tune the process allocator to retain freed memory for reuse. OpenFHE operations allocate and
// free many large (~0.5-30 MB) buffers; on allocators that return freed buffers to the OS right
// away, re-faulting the pages on the next operation can dominate single-threaded runtime. Any
// tuning below runs once, process-wide, at library load. NOTE: retained memory shows up as a
// higher resident set size for workloads with large transient allocation peaks. Use AllocTrim()
// after large allocations are freed if this becomes an issue, or build with
// -DWITH_MALLOC_TUNING=OFF to disable this tuning entirely.
namespace {
#if defined(__APPLE__)
// Nothing to tune: macOS libmalloc already retains freed memory in-process. Freed pages of
// small/medium allocations stay mapped and are marked reusable (the kernel reclaims them only
// under memory pressure), and freed large allocations are held in the default zone's cache.
// There is no public API to tune this behavior further; AllocTrim() releases these caches.
#elif defined(__GLIBC__)
// By default glibc returns freed large buffers to the OS (brk heap-trim / munmap) and re-faults
// the pages on the next operation. Keeping large allocations on the heap (M_MMAP_MAX=0) and
// never trimming it back to the OS (M_TRIM_THRESHOLD=-1) lets the buffers be reused,
// eliminating the churn.
[[maybe_unused]] const bool ofheGlibcMallocTuned = []() noexcept {
mallopt(M_MMAP_MAX, 0);
mallopt(M_TRIM_THRESHOLD, -1);
return true;
}();
#elif defined(_MSC_VER)
// Nothing to tune: the CRT heap is the Windows process heap, which serves allocations above
// roughly 0.5-1 MB directly via VirtualAlloc and returns them to the OS on free, with no
// supported process-wide switch to retain them. If this churn matters, link a caching
// allocator (e.g. mimalloc or tcmalloc) instead.
#endif
} // namespace
#endif

Expand All @@ -67,16 +87,24 @@ namespace {
// Not async-signal-safe and acquires allocator locks; call only from normal execution context,
// never from a signal handler. Returns true if a trim was attempted, false on unsupported builds.
bool AllocTrim() {
#if defined(__GLIBC__)
#if defined(__APPLE__)
malloc_zone_pressure_relief(nullptr, 0);
return true;
#elif defined(__GLIBC__)
malloc_trim(0);
return true;
#elif defined(_MSC_VER)
_heapmin();
return true;
#else
return false;
#endif
}

// secure_memset() overwrites memory with c and, unlike a plain std::memset() of an object about
// to be freed or go out of scope, is guaranteed not to be removed by dead-store elimination.
void secure_memset(volatile void* mem, uint8_t c, size_t len) {
volatile uint8_t* ptr = (volatile uint8_t*)mem;
volatile uint8_t* ptr = static_cast<volatile uint8_t*>(mem);
for (size_t i = 0; i < len; ++i)
*(ptr + i) = c;
}
Expand Down
16 changes: 12 additions & 4 deletions src/pke/include/cryptocontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,16 +626,24 @@ class CryptoContextImpl : public Serializable {
* @brief Clear CKKS bootstrap precomputations cached by this context's scheme.
*/
void ClearBootstrapPrecom() noexcept {
VerifyCKKSScheme(__func__);
m_scheme->ClearBootstrapPrecom();
if (m_scheme)
m_scheme->ClearBootstrapPrecom();
}

/**
* @brief Clear CKKS/FHEW scheme-switch precomputations cached by this context's scheme.
*/
void ClearSchemeSwitchPrecom() noexcept {
VerifyCKKSScheme(__func__);
m_scheme->ClearSchemeSwitchPrecom();
if (m_scheme)
m_scheme->ClearSchemeSwitchPrecom();
}

/**
* @brief Release all scheme-level caches (bootstrap + scheme-switch).
*/
void ClearAllCKKSCaches() noexcept {
ClearBootstrapPrecom();
ClearSchemeSwitchPrecom();
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/pke/include/cryptocontextfactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class CryptoContextFactory {

public:
static void ReleaseAllContexts() {
for (auto& cc : AllContexts) {
if (cc)
cc->ClearAllCKKSCaches();
}
if (!AllContexts.empty())
AllContexts[0]->ClearStaticMapsAndVectors();
AllContexts.clear();
Expand Down
8 changes: 4 additions & 4 deletions src/pke/include/schemebase/base-scheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -1147,13 +1147,13 @@ class SchemeBase {
}

void ClearBootstrapPrecom() noexcept {
VerifyFHEEnabled(__func__);
m_FHE->ClearBootstrapPrecom();
if (m_FHE)
m_FHE->ClearBootstrapPrecom();
}

void ClearSchemeSwitchPrecom() noexcept {
VerifySchemeSwitchEnabled(__func__);
m_SchemeSwitch->ClearSchemeSwitchPrecom();
if (m_SchemeSwitch)
m_SchemeSwitch->ClearSchemeSwitchPrecom();
}

std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> EvalBootstrapKeyGen(const PrivateKey<Element> privateKey,
Expand Down
9 changes: 6 additions & 3 deletions src/pke/unittest/utckksrns/UnitTestCKKSCacheClear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@
//==================================================================================

#include "binfhecontext.h"
#include "gtest/gtest.h"
#include "openfhe.h"
#include "scheme/ckksrns/ckksrns-fhe.h"
#include "scheme/ckksrns/ckksrns-schemeswitching.h"
#include "scheme/scheme-swch-params.h"
#include "utils/memory.h"

#include "gtest/gtest.h"

#include <vector>

#if defined(__GLIBC__)
Expand Down Expand Up @@ -116,9 +115,13 @@ CryptoContext<DCRTPoly> MakeSchemeSwitchCC() {

class UTCKKSCacheClear : public ::testing::Test {
protected:
#if defined(WITH_TCM)
#if defined(WITH_TCM) || defined(__EMSCRIPTEN__)
void SetUp() override {
#if defined(WITH_TCM)
GTEST_SKIP() << "Heap usage checks are not stable with tcmalloc enabled";
#else
GTEST_SKIP() << "Heap probe unavailable under Emscripten";
#endif
}
#endif

Expand Down
Loading
Loading