From bf5a5f1ba62aa6a7745d7969263fe20cdc151a68 Mon Sep 17 00:00:00 2001 From: Wandering Consciousness <10329002+Wandering-Consciousness@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:42:04 +1200 Subject: [PATCH 1/3] add MeterFeeder submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitmodules b/.gitmodules index f9aea52fd..9d099e1c5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "libpsirngclient"] path = libpsirngclient url = https://github.com/nullspook/libpsirngclient.git +[submodule "meterfeeder"] + path = meterfeeder + url = https://github.com/vfp2/MeterFeeder.git From 1cb8a776dee31b4e2f178e47774d41bc2932266a Mon Sep 17 00:00:00 2001 From: Wandering Consciousness <10329002+Wandering-Consciousness@users.noreply.github.com> Date: Thu, 3 Jul 2025 00:00:33 +1200 Subject: [PATCH 2/3] initial commit of MeterFeeder implementation --- README.md | 51 +++++++++++++++++++--- src/CMakeLists.txt | 6 +++ src/llama-sampling.cpp | 16 +++++-- src/llama-sampling.h | 30 +++++++++++++ src/llama.cpp | 99 ++++++++++++++++++++++++++++++++++++------ 5 files changed, 181 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5e6088f82..b461d2c98 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,17 @@ quantum-llama.cpp is a modified [llama.cpp](https://github.com/ggml-org/llama.cpp) that uses Quantum World Corporation (QWC) / ComScire QRNGs (Quantum Random -Number Generators) to generate the tokens. While the output may be -indistinguishable from the original llama.cpp, it introduces a poetic idea, -_"the output is co-authored by the universe itself."_ +Number Generators) or MeterFeeder hardware RNG devices to generate the tokens. +While the output may be indistinguishable from the original llama.cpp, it introduces +a poetic idea, _"the output is co-authored by the universe itself."_ -To use quantum-llama.cpp, you need to have a running [psirng](https://github.com/nullspook/psirng) +## Random Number Generator Options + +quantum-llama.cpp supports two RNG systems: + +### Option 1: PsiRNG (Network-based Quantum RNG) + +To use PsiRNG, you need to have a running [psirng](https://github.com/nullspook/psirng) server. Set `PSIRNG_HOST`, `PSIRNG_GRPC_PORT`, and `PSIRNG_CERT_PATH` environment variables before running `llama-*` programs. @@ -19,7 +25,7 @@ cd quantum-llama.cpp cmake -B build cmake --build build --config Release -# Set environment variables +# Set environment variables for PsiRNG export PSIRNG_HOST=192.0.2.10 export PSIRNG_GRPC_PORT=50051 export PSIRNG_CERT_PATH=/path/to/cert.pem @@ -29,6 +35,41 @@ cd build/bin ./llama-cli -m /path/to/model.gguf -p "I believe the meaning of life is" -n 128 ``` +### Option 2: MeterFeeder (Hardware RNG) + +To use MeterFeeder hardware RNG devices, set the `METERFEEDER_USE_DEVICE` +environment variable with your device serial number. + +```bash +# Clone +git clone --recurse-submodules https://github.com/nullspook/quantum-llama.cpp.git +cd quantum-llama.cpp + +# Build MeterFeeder library +cd meterfeeder +chmod +x linux-build-lib.sh +./linux-build-lib.sh +cd .. + +# Build quantum-llama.cpp +cmake -B build +cmake --build build --config Release + +# Set environment variable for MeterFeeder +export METERFEEDER_USE_DEVICE="your_device_serial_number" + +# Run +cd build/bin +./llama-cli -m /path/to/model.gguf -p "I believe the meaning of life is" -n 128 +``` + +### Automatic Detection + +The system automatically detects which RNG to use based on environment variables: +- If `METERFEEDER_USE_DEVICE` is set, it uses MeterFeeder +- If `PSIRNG_HOST`, `PSIRNG_GRPC_PORT`, and `PSIRNG_CERT_PATH` are set, it uses PsiRNG +- If neither is configured, the system will exit with an error + **Note:** quantum-llama.cpp must be built using `cmake`. --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d7374ffa9..1c3e2729d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,12 @@ target_compile_features (llama PUBLIC cxx_std_11) # don't bump target_link_libraries(llama PUBLIC ggml psirngclient) +# Add MeterFeeder library if it exists +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../meterfeeder/builds/linux/libmeterfeeder.so") + target_link_libraries(llama PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../meterfeeder/builds/linux/libmeterfeeder.so") + target_link_directories(llama PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../meterfeeder/builds/linux") +endif() + if (BUILD_SHARED_LIBS) set_target_properties(llama PROPERTIES POSITION_INDEPENDENT_CODE ON) target_compile_definitions(llama PRIVATE LLAMA_SHARED LLAMA_BUILD) diff --git a/src/llama-sampling.cpp b/src/llama-sampling.cpp index 9111fc182..989dae96f 100644 --- a/src/llama-sampling.cpp +++ b/src/llama-sampling.cpp @@ -628,9 +628,19 @@ llama_token llama_sample_token_with_rng_impl(struct llama_sampling * smpl, llama int idx; double u; - int rand_result = psirngclient_randuniform(smpl->psirngclient_ptr, &u, 1, 0.0, 1.0); - if (rand_result != PSIRNGCLIENT_RESULT_OK) { - GGML_ABORT("psirngclient_randuniform error: %d", rand_result); + if (smpl->use_meterfeeder) { + // Use MeterFeeder for random number generation + char error_reason[256]; + u = MF_RandUniform(smpl->meterfeeder_serial_number, error_reason); + if (strlen(error_reason) > 0) { + GGML_ABORT("MF_RandUniform error: %s", error_reason); + } + } else { + // Use PsiRNGClient for random number generation + int rand_result = psirngclient_randuniform(smpl->psirngclient_ptr, &u, 1, 0.0, 1.0); + if (rand_result != PSIRNGCLIENT_RESULT_OK) { + GGML_ABORT("psirngclient_randuniform error: %d", rand_result); + } } idx = static_cast(std::distance(cdf.begin(), std::lower_bound(cdf.begin(), cdf.end(), u))); diff --git a/src/llama-sampling.h b/src/llama-sampling.h index 4c0496230..06e5f4099 100644 --- a/src/llama-sampling.h +++ b/src/llama-sampling.h @@ -4,13 +4,43 @@ #include "psirngclient.h" +// MeterFeeder function declarations +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize the connected generators +int MF_Initialize(char* pErrorReason); + +// Get the number of connected and successfully initialized generators +int MF_GetNumberGenerators(); + +// Get the list of connected and successfully initialized generators +// Array element format: +int MF_GetSerialListGeneratorsWithSize(char** pGenerators, int arraySize); + +// Get a random floating point number between [0,1) +double MF_RandUniform(char* generatorSerialNumber, char* pErrorReason); + +// Shutdown and de-initialize all the generators +void MF_Shutdown(); + +#ifdef __cplusplus +} +#endif + struct llama_sampling { llama_sampling(int32_t n_vocab) : n_vocab(n_vocab) {} std::mt19937 rng; + // PsiRNGClient support psirngclient * psirngclient_ptr; + // MeterFeeder support + char* meterfeeder_serial_number; + bool use_meterfeeder; + int32_t n_vocab = 0; mutable int64_t t_sample_us = 0; diff --git a/src/llama.cpp b/src/llama.cpp index e6d9d8802..6e4bb5b99 100644 --- a/src/llama.cpp +++ b/src/llama.cpp @@ -3191,6 +3191,12 @@ struct llama_context { } ggml_backend_buffer_free(buf_output); + + // Clean up MeterFeeder resources + if (sampling.use_meterfeeder) { + delete[] sampling.meterfeeder_serial_number; + MF_Shutdown(); + } } const struct llama_model & model; @@ -18195,28 +18201,95 @@ struct llama_context * llama_new_context_with_model( ctx->sampling.rng = std::mt19937(params.seed); ctx->sampling.psirngclient_ptr = nullptr; + ctx->sampling.meterfeeder_serial_number = nullptr; + ctx->sampling.use_meterfeeder = false; + + // Check for MeterFeeder configuration first + const char* meterfeeder_device = std::getenv("METERFEEDER_USE_DEVICE"); + if (meterfeeder_device != nullptr) { + // Initialize MeterFeeder + char error_reason[256]; + if (int result = MF_Initialize(error_reason); result != 0) { + LLAMA_LOG_ERROR("%s: failed to initialize MeterFeeder: %s\n", __func__, error_reason); + llama_free(ctx); + return nullptr; + } - const char* psirng_host = std::getenv("PSIRNG_HOST"); - const char* psirng_grpc_port = std::getenv("PSIRNG_GRPC_PORT"); - const char* psirng_cert_path = std::getenv("PSIRNG_CERT_PATH"); + // Check if the specified device exists + int num_generators = MF_GetNumberGenerators(); + if (num_generators <= 0) { + LLAMA_LOG_ERROR("%s: no MeterFeeder devices found\n", __func__); + llama_free(ctx); + return nullptr; + } - if (psirng_host != nullptr && psirng_grpc_port != nullptr && psirng_cert_path != nullptr) { - if (int result = psirngclient_init(&ctx->sampling.psirngclient_ptr, psirng_host, std::stoi(psirng_grpc_port), psirng_cert_path); result != PSIRNGCLIENT_RESULT_OK) { - LLAMA_LOG_ERROR("%s: failed to initialize psirng client: %d\n", __func__, result); + // Get list of generators and check if our device is in the list + char** generators = new char*[num_generators]; + for (int i = 0; i < num_generators; i++) { + generators[i] = new char[256]; + } + + int result = MF_GetSerialListGeneratorsWithSize(generators, num_generators); + if (result != num_generators) { + LLAMA_LOG_ERROR("%s: failed to get MeterFeeder device list\n", __func__); + for (int i = 0; i < num_generators; i++) { + delete[] generators[i]; + } + delete[] generators; llama_free(ctx); return nullptr; } - if (!psirngclient_ishealthy(ctx->sampling.psirngclient_ptr)) { - LLAMA_LOG_ERROR("%s: psirng is not healthy\n", __func__); + + bool device_found = false; + for (int i = 0; i < num_generators; i++) { + if (strcmp(generators[i], meterfeeder_device) == 0) { + device_found = true; + break; + } + } + + // Clean up generators array + for (int i = 0; i < num_generators; i++) { + delete[] generators[i]; + } + delete[] generators; + + if (!device_found) { + LLAMA_LOG_ERROR("%s: MeterFeeder device '%s' not found\n", __func__, meterfeeder_device); llama_free(ctx); return nullptr; - } else { - LLAMA_LOG_INFO("%s: Using psirng running on %s:%s\n", __func__, psirng_host, psirng_grpc_port); } + + // Store the device serial number + ctx->sampling.meterfeeder_serial_number = new char[strlen(meterfeeder_device) + 1]; + strcpy(ctx->sampling.meterfeeder_serial_number, meterfeeder_device); + ctx->sampling.use_meterfeeder = true; + + LLAMA_LOG_INFO("%s: Using MeterFeeder device: %s\n", __func__, meterfeeder_device); } else { - LLAMA_LOG_ERROR("%s: psirng is not configured\n", __func__); - llama_free(ctx); - return nullptr; + // Fall back to PsiRNGClient configuration + const char* psirng_host = std::getenv("PSIRNG_HOST"); + const char* psirng_grpc_port = std::getenv("PSIRNG_GRPC_PORT"); + const char* psirng_cert_path = std::getenv("PSIRNG_CERT_PATH"); + + if (psirng_host != nullptr && psirng_grpc_port != nullptr && psirng_cert_path != nullptr) { + if (int result = psirngclient_init(&ctx->sampling.psirngclient_ptr, psirng_host, std::stoi(psirng_grpc_port), psirng_cert_path); result != PSIRNGCLIENT_RESULT_OK) { + LLAMA_LOG_ERROR("%s: failed to initialize psirng client: %d\n", __func__, result); + llama_free(ctx); + return nullptr; + } + if (!psirngclient_ishealthy(ctx->sampling.psirngclient_ptr)) { + LLAMA_LOG_ERROR("%s: psirng is not healthy\n", __func__); + llama_free(ctx); + return nullptr; + } else { + LLAMA_LOG_INFO("%s: Using psirng running on %s:%s\n", __func__, psirng_host, psirng_grpc_port); + } + } else { + LLAMA_LOG_ERROR("%s: neither MeterFeeder nor psirng is configured\n", __func__); + llama_free(ctx); + return nullptr; + } } ctx->logits_all = params.logits_all; From fdce35aade1ff74623d06b5c916ee06dd5fc3efb Mon Sep 17 00:00:00 2001 From: Wandering Consciousness <10329002+Wandering-Consciousness@users.noreply.github.com> Date: Thu, 3 Jul 2025 00:22:54 +1200 Subject: [PATCH 3/3] fix MeterFeeder init error --- src/llama.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llama.cpp b/src/llama.cpp index 6e4bb5b99..347559a4b 100644 --- a/src/llama.cpp +++ b/src/llama.cpp @@ -18209,7 +18209,7 @@ struct llama_context * llama_new_context_with_model( if (meterfeeder_device != nullptr) { // Initialize MeterFeeder char error_reason[256]; - if (int result = MF_Initialize(error_reason); result != 0) { + if (int result = MF_Initialize(error_reason); result != 1) { LLAMA_LOG_ERROR("%s: failed to initialize MeterFeeder: %s\n", __func__, error_reason); llama_free(ctx); return nullptr;