From c6545725fc09ea7ad6ac0e30f80f3b2597c0171e Mon Sep 17 00:00:00 2001 From: Olasoji Denloye Date: Fri, 8 May 2026 13:58:58 -0700 Subject: [PATCH 1/3] logging: add LOG_DEBUG level; qat: map log level to QATzip log level (#56) * Adds test to validate log_stats_samples config Signed-off-by: Olasoji * Reduces excessive error logging in QAT mode Signed-off-by: Olasoji * Bugfix for the log stream Signed-off-by: Olasoji * Treats QPL_STS_MORE_OUTPUT_NEEDED as a non error condition for IAA Signed-off-by: Olasoji * Fixed formatting Signed-off-by: Olasoji * - Modifies iaa behavior so that when QPL_STS_MORE_OUTPUT_NEEDED is returned eos isnt erronously set. Signed-off-by: Olasoji * -Adds proper formatting Signed-off-by: Olasoji * logging: add LOG_DEBUG level; qat: map log level to QATzip log level Introduce LOG_DEBUG (value=1) as the most verbose log level, shifting LOG_INFO to 2 and LOG_ERROR to 3. This follows the conventional ordering used by syslog, Log4j, Python logging, and QATzip itself (where higher values mean more verbose). The default log level remains LOG_ERROR (now value=3), so existing deployments see no behavioral change unless they explicitly set a lower value in /etc/zlib-accel.conf. The config parser max for log_level is updated from 2 to 3 accordingly. In qat.cpp, replace the hardcoded qzSetLogLevel(LOG_NONE) with a dynamic mapping from the configured log_level: LOG_DEBUG -> LOG_DEBUG3 (maximum QATzip verbosity) LOG_INFO -> LOG_INFO LOG_ERROR -> LOG_ERROR default -> LOG_NONE This corrects an inversion present in PR #55 of intel/zlib-accel, where LOG_ERROR was incorrectly mapped to LOG_DEBUG3. New tests: LogDebugLevel, LogDebugFilteredByInfo; LogLevelFiltering extended to cover DEBUG filtering. Builds on: intel/zlib-accel#55 Signed-off-by: Olasoji * Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * qat: gate qzSetLogLevel mapping behind DEBUG_LOG; apply formatting Without the DEBUG_LOG guard, a release build (DEBUG_LOG=OFF) with a non-zero log_level in the config would cause QATzip to emit verbose output, contradicting the documented behaviour that log_level only applies when built with DEBUG_LOG=ON. Gate the dynamic mapping behind #ifdef DEBUG_LOG and unconditionally set LOG_NONE in the else branch, matching the original behaviour for non-debug builds. Addresses Copilot review comment on PR #56. Signed-off-by: Olasoji * address review comments: enum ordering, call_once, explicit LOG_NONE case - logging.h: reorder LogLevel enum to match QATzip's QzLogLevel_T convention {LOG_NONE=0, LOG_ERROR=1, LOG_INFO=2, LOG_DEBUG=3}; flip filter direction from 'level < config' to 'level > config' so higher values = more verbose. Apply same fix to PrintDeflateBlockHeader. - qat.cpp: call qzSetLogLevel once per process via std::call_once instead of per session; add explicit case LogLevel::LOG_NONE; move default to end with comment; restructure #ifdef to be inside the once lambda. - config/config.cpp, config/default_config: update default log_level from 3 to 1 (LOG_ERROR = errors only, matching previous error-only default). - README.md: update log_level documentation to describe new ordering. - tests/zlib_accel_test.cpp: update expected log_level default to 1. --------- Signed-off-by: Olasoji Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 5 ++-- config/config.cpp | 4 ++-- config/default_config | 2 +- logging.h | 16 ++++++++++--- qat.cpp | 32 ++++++++++++++++++++++++- tests/logging_test.cpp | 50 +++++++++++++++++++++++++++++++++++---- tests/zlib_accel_test.cpp | 2 +- 7 files changed, 97 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b36a23b..4ed2712 100644 --- a/README.md +++ b/README.md @@ -212,9 +212,10 @@ ignore_zlib_dictionary - If set to 0, zlib-accel honors inflateSetDictionary and deflateSetDictionary. log_level -- Values: 0,1,2. Default 2 +- Values: 0,1,2,3. Default: 1 - This option applies only if the shim is built with DEBUG_LOG=ON. -- If 1, error and info log messages are shown. If 2, only error log messages are shown. If 0, no log messages are shown. +- Matches QATzip's verbosity convention: 0 = silent, 1 = errors only, 2 = info and errors, 3 = debug, info, and errors (most verbose). +- Migration note: the numeric meanings changed from earlier versions. Older configurations that used `log_level=2` for error-only output must now use `log_level=1`. Review existing `log_level` settings when upgrading. log_stats_samples - Values: 0-INT_MAX. Default 1000 diff --git a/config/config.cpp b/config/config.cpp index 29f93cf..aefe066 100644 --- a/config/config.cpp +++ b/config/config.cpp @@ -28,7 +28,7 @@ uint32_t configs[CONFIG_MAX] = { 1, /*qat_compression_level*/ 0, /*qat_compression_allow_chunking*/ 0, /*ignore_zlib_dictionary*/ - 2, /*log_level*/ + 1, /*log_level*/ 1000 /*log_stats_samples*/ }; @@ -85,7 +85,7 @@ bool LoadConfigFile(std::string& file_content, const char* file_path) { trySetConfig(QAT_COMPRESSION_LEVEL, 9, 1); trySetConfig(QAT_COMPRESSION_ALLOW_CHUNKING, 1, 0); trySetConfig(IGNORE_ZLIB_DICTIONARY, 1, 0); - trySetConfig(LOG_LEVEL, 2, 0); + trySetConfig(LOG_LEVEL, 3, 0); trySetConfig(LOG_STATS_SAMPLES, UINT32_MAX, 0); config_reader.GetValue("log_file", log_file); diff --git a/config/default_config b/config/default_config index 6ae0cc8..827b7b2 100644 --- a/config/default_config +++ b/config/default_config @@ -11,5 +11,5 @@ qat_periodical_polling = 0 qat_compression_level = 1 qat_compression_allow_chunking = 0 ignore_zlib_dictionary = 0 -log_level = 2 +log_level = 1 log_file = /tmp/zlib-accel.log diff --git a/logging.h b/logging.h index b5e8301..d384cdb 100644 --- a/logging.h +++ b/logging.h @@ -15,7 +15,14 @@ using namespace config; -enum class LogLevel { LOG_NONE = 0, LOG_INFO = 1, LOG_ERROR = 2 }; +// Log verbosity levels. 0 = silent; higher values = more verbose. +// Matches QATzip's QzLogLevel_T convention. +enum class LogLevel { + LOG_NONE = 0, + LOG_ERROR = 1, + LOG_INFO = 2, + LOG_DEBUG = 3 +}; #if defined(DEBUG_LOG) || defined(ENABLE_STATISTICS) @@ -56,7 +63,7 @@ inline void Log(LogLevel level, Args&&... args) { return; } - if (static_cast(level) < current_level) { + if (static_cast(level) > current_level) { return; } @@ -69,6 +76,9 @@ inline void Log(LogLevel level, Args&&... args) { case LogLevel::LOG_INFO: stream << "Info: "; break; + case LogLevel::LOG_DEBUG: + stream << "Debug: "; + break; case LogLevel::LOG_NONE: return; } @@ -105,7 +115,7 @@ inline void PrintDeflateBlockHeader(LogLevel level, uint8_t* data, uint32_t len, return; } - if (static_cast(level) < current_level) { + if (static_cast(level) > current_level) { return; } diff --git a/qat.cpp b/qat.cpp index d5bc57e..e897479 100644 --- a/qat.cpp +++ b/qat.cpp @@ -99,8 +99,38 @@ void QATJob::Init(QzSessionPtr &qzSession, CompressedFormat format, return; } + // Map zlib-accel log level to QATzip log level. + // qzSetLogLevel is a QATzip global; call it once per process regardless + // of how many QAT sessions are created. + static std::once_flag qz_log_level_flag; + std::call_once(qz_log_level_flag, []() { + QzLogLevel_T qzLogLevel = LOG_NONE; +#ifdef DEBUG_LOG + LogLevel logLevel = + static_cast(config::GetConfig(config::LOG_LEVEL)); + switch (logLevel) { + case LogLevel::LOG_NONE: + qzLogLevel = LOG_NONE; + break; + case LogLevel::LOG_ERROR: + qzLogLevel = LOG_ERROR; + break; + case LogLevel::LOG_INFO: + qzLogLevel = LOG_INFO; + break; + case LogLevel::LOG_DEBUG: + qzLogLevel = LOG_DEBUG3; + break; + default: + // Unreachable: all LogLevel values are handled above. + qzLogLevel = LOG_NONE; + break; + } +#endif + qzSetLogLevel(qzLogLevel); + }); + // Initialize QAT hardware - qzSetLogLevel(LOG_NONE); int status = qzInit(session.get(), 0); if (status != QZ_OK && status != QZ_DUPLICATE) { Log(LogLevel::LOG_ERROR, "qzInit() failure Line ", __LINE__, " session ", diff --git a/tests/logging_test.cpp b/tests/logging_test.cpp index b359208..c00f7e1 100644 --- a/tests/logging_test.cpp +++ b/tests/logging_test.cpp @@ -152,6 +152,46 @@ TEST_F(LoggingTest, LogErrorLevel) { EXPECT_NE(c.find("error occurred"), std::string::npos); } +/** + * @test Verifies that DEBUG-level messages appear when LOG_LEVEL=DEBUG. + */ +TEST_F(LoggingTest, LogDebugLevel) { + CreateLogFile(test_log_file.c_str()); + config::SetConfig(config::LOG_LEVEL, + static_cast(LogLevel::LOG_DEBUG)); + + Log(LogLevel::LOG_DEBUG, "debug message"); + CloseLogFile(); + + std::ifstream f(test_log_file); + std::string c((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); + + EXPECT_NE(c.find("Debug:"), std::string::npos); + EXPECT_NE(c.find("debug message"), std::string::npos); +} + +/** + * @test Verifies that DEBUG-level messages are filtered out when + * LOG_LEVEL=INFO. + */ +TEST_F(LoggingTest, LogDebugFilteredByInfo) { + CreateLogFile(test_log_file.c_str()); + config::SetConfig(config::LOG_LEVEL, + static_cast(LogLevel::LOG_INFO)); + + Log(LogLevel::LOG_DEBUG, "filtered debug"); // Should NOT appear + Log(LogLevel::LOG_INFO, "visible info"); // Should appear + CloseLogFile(); + + std::ifstream f(test_log_file); + std::string c((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); + + EXPECT_EQ(c.find("filtered debug"), std::string::npos); + EXPECT_NE(c.find("visible info"), std::string::npos); +} + /** * @test Verifies that LOG_NONE prevents any message from being logged. */ @@ -191,7 +231,7 @@ TEST_F(LoggingTest, LogMultipleArguments) { /** * @test Validates that log-level filtering works correctly: - * - INFO log should be filtered out under LOG_ERROR + * - DEBUG and INFO logs should be filtered out under LOG_ERROR * - ERROR log should appear. */ TEST_F(LoggingTest, LogLevelFiltering) { @@ -199,15 +239,17 @@ TEST_F(LoggingTest, LogLevelFiltering) { config::SetConfig(config::LOG_LEVEL, static_cast(LogLevel::LOG_ERROR)); - Log(LogLevel::LOG_INFO, "filtered"); // Should NOT appear - Log(LogLevel::LOG_ERROR, "visible"); // Should appear + Log(LogLevel::LOG_DEBUG, "filtered debug"); // Should NOT appear + Log(LogLevel::LOG_INFO, "filtered info"); // Should NOT appear + Log(LogLevel::LOG_ERROR, "visible"); // Should appear CloseLogFile(); std::ifstream f(test_log_file); std::string c((std::istreambuf_iterator(f)), std::istreambuf_iterator()); - EXPECT_EQ(c.find("filtered"), std::string::npos); + EXPECT_EQ(c.find("filtered debug"), std::string::npos); + EXPECT_EQ(c.find("filtered info"), std::string::npos); EXPECT_NE(c.find("visible"), std::string::npos); } diff --git a/tests/zlib_accel_test.cpp b/tests/zlib_accel_test.cpp index c8ec0ce..61a7189 100644 --- a/tests/zlib_accel_test.cpp +++ b/tests/zlib_accel_test.cpp @@ -1274,7 +1274,7 @@ TEST_F(ConfigLoaderTest, LoadValidConfig) { EXPECT_EQ(GetConfig(USE_IAA_UNCOMPRESS), 0); EXPECT_EQ(GetConfig(USE_ZLIB_COMPRESS), 1); EXPECT_EQ(GetConfig(USE_ZLIB_UNCOMPRESS), 1); - EXPECT_EQ(GetConfig(LOG_LEVEL), 2); + EXPECT_EQ(GetConfig(LOG_LEVEL), 1); LoadConfigFile(file_content); } From 15bf6e71db7334332121c58227899a6d0dd515ef Mon Sep 17 00:00:00 2001 From: Olasoji Date: Wed, 15 Jul 2026 13:05:05 -0700 Subject: [PATCH 2/3] igzip: rename deflateSetDictionary/inflateSetDictionary to IGZIP variants Rename deflateSetDictionary and inflateSetDictionary in igzip.cpp to DeflateSetDictionaryIGZIP and InflateSetDictionaryIGZIP to eliminate the duplicate symbol conflict with the ZEXPORT versions in zlib_accel.cpp. The functions are stubs for future dictionary support (pending performance validation). Add declarations to igzip.h for when they are wired in. --- igzip.cpp | 8 ++++---- igzip.h | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/igzip.cpp b/igzip.cpp index 1f0d232..7776b08 100644 --- a/igzip.cpp +++ b/igzip.cpp @@ -262,8 +262,8 @@ int EndCompressIGZIP(struct isal_zstream *isal_strm) { return Z_OK; } -int deflateSetDictionary(z_streamp strm, unsigned char *dict_data, - unsigned int dict_len) { +int DeflateSetDictionaryIGZIP(z_streamp strm, unsigned char *dict_data, + unsigned int dict_len) { if (!strm || !strm->state || !dict_data || dict_len == 0) return Z_STREAM_ERROR; @@ -498,8 +498,8 @@ int EndUncompressIGZIP(struct inflate_state *isal_strm_inflate) { return Z_OK; } -int inflateSetDictionary(z_streamp strm, unsigned char *dict_data, - unsigned int dict_len) { +int InflateSetDictionaryIGZIP(z_streamp strm, unsigned char *dict_data, + unsigned int dict_len) { if (!strm || !strm->state || !dict_data || dict_len == 0) return Z_STREAM_ERROR; diff --git a/igzip.h b/igzip.h index 5cc4948..4d53321 100644 --- a/igzip.h +++ b/igzip.h @@ -58,5 +58,9 @@ int UncompressIGZIP(struct inflate_state *isal_strm_inflate, const unsigned long *total_out, bool *end_of_stream); int EndUncompressIGZIP(struct inflate_state *isal_strm_inflate); int ResetUncompressIGZIP(struct inflate_state *isal_strm_inflate); +int DeflateSetDictionaryIGZIP(z_streamp strm, unsigned char *dict_data, + unsigned int dict_len); +int InflateSetDictionaryIGZIP(z_streamp strm, unsigned char *dict_data, + unsigned int dict_len); // #define Z_DEFAULT_COMPRESSION 6 #endif From 6d4f3daa4dc984439cc2cd20b78da081243392b4 Mon Sep 17 00:00:00 2001 From: Olasoji Date: Wed, 15 Jul 2026 14:06:28 -0700 Subject: [PATCH 3/3] sharded_map: add missing #include for std::unique_lock std::unique_lock is defined in , not . On GCC 13+ (Ubuntu 24.04), transitively includes making this invisible. On GCC 11 (Ubuntu 22.04) the include is not pulled in and the build fails with 'std::unique_lock is not a member of std'. Add explicit include for standard compliance. Reported by matt-welch in PR #61 review. --- sharded_map.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sharded_map.h b/sharded_map.h index ab8dda8..debb87e 100644 --- a/sharded_map.h +++ b/sharded_map.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include