Базовая трассировка (tracing) и спаны вокруг основных операций
Цель
Включить систему трассировки на базе tracing и покрыть основными спанами критические операции гомоморфной арифметики (без погружения в математику). Это упростит профилирование, поиск регрессий и контроль бюджета масштаба/уровней.
Результат (Acceptance Criteria)
- Подключены
tracing,tracing-subscriber(сEnvFilter), единый инициализатор логов. - Для операций есть спаны с единым набором полей:
-
op: имя операции (encode,decode,add,mul_coeff,mul_ntt,relinearize,rescale,mod_up,mod_down,ntt_fwd,ntt_inv) -
degree: полиномиальная степень -
levels: текущее число уровней / индекс уровня -
scale: текущий масштаб (как число с плавающей точкой или лог? и вообще нужно ли это) -
mod_bits: суммарная/текущая битность модуля (нужно ли? хотя было бы неплохо смотреть текущий бюджет по битности....) -
elapsed_us: время выполнения (микросекунды) — пишется в конце операции
-
- Добавлен флаг
trace-verbose(feature), который включает подробные события (например, размеры векторов, id простых модулей, флаги NTT-формы), но по умолчанию скрыт. - Минимальные тесты, проверяющие, что спаны создаются (с захватом логов).
- Документация: как включить трассировку и какие поля смотреть.
Подзадачи
-
Зависимости и инициализация
- Добавить зависимости:
tracing-
tracing-subscriberс фичейenv-filter
- Инициализатор (один раз при старте библиотеки/примеров):
use tracing_subscriber::{fmt, EnvFilter}; pub fn init_tracing() { let _ = fmt() .with_env_filter(EnvFilter::from_default_env()) .with_target(false) .try_init(); } - Док: использовать
RUST_LOG/RUST_TRACING:RUST_LOG=info cargo test RUST_LOG=debug cargo run --example primes
- Добавить зависимости:
-
Соглашение по полям и именованию
- Ввести константы/хелперы для единообразных полей спанов.
- Пример:
use tracing::{info_span, Instrument}; fn with_span<F, T>(op: &str, degree: usize, levels: usize, scale: f64, mod_bits: u32, f: F) -> T where F: FnOnce() -> T, { let span = info_span!( "he_op", op, degree, levels, scale = %format!("{:.3e}", scale), mod_bits ); let start = std::time::Instant::now(); let res = (|| f()).instrument(span.clone()).call_once(()); let _ = span.record("elapsed_us", &tracing::field::display(start.elapsed().as_micros())); res } - Поле
elapsed_usзаполнять по завершении операции.
-
Спаны вокруг ключевых операций
- Обернуть следующие места:
- Кодирование/декодирование:
encode,decode - Сложение:
add(иadd_assign) - Умножение:
mul_coeff(в коэфф. области),mul_ntt(в NTT-области) - Релинеаризация:
relinearize - Рескейл:
rescale - Изменение базы модулей:
mod_up,mod_down - Преобразования:
ntt_fwd,ntt_inv
- Кодирование/декодирование:
- Внутри спанов логировать ключевые события
tracing::debug!(только приtrace-verbose):- размеры массивов, количество простых модулей
- флаг
is_ntt - id удаляемого/добавляемого простого модуля при mod_down/up
- Обернуть следующие места:
-
Фича-флаг
trace-verbose- В
Cargo.toml:[features] trace-verbose = [] - Гвардить подробные
debug!и потенциально дорогие вычисления строк с помощью#[cfg(feature = "trace-verbose")].
- В
-
Мини-тесты на спаны
- Тесты, запускающие одну-две операции и проверяющие, что:
- инициализация не паникует
- спан создаётся (через
tracing_subscriber::fmt::Subscriber::builder().with_test_writer()и проверку вывода/формата)
- Smoke-тест:
addиntt_fwdсоздают поляop,degree,levels,scale,mod_bits.
- Тесты, запускающие одну-две операции и проверяющие, что:
-
Документация
- Раздел в
docs/или вREADME: как включать трассировку:- примеры
RUST_LOG=he_op=info,homomorphix_rs=debug - пример вывода и расшифровка полей
- примеры
- Рекомендации по профилированию (фильтры для тяжёлых операций).
- Раздел в
Примеры запуска
# Базовый инфо-уровень
RUST_LOG=info cargo test -q
# Детальный для нашей библиотеки
RUST_LOG=homomorphix_rs=debug cargo run --example debug_primitive_root
# Включить подробные сообщения (feature) (нужно ли?)
RUST_LOG=debug cargo test --features trace-verbose