Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package clpeak for openSUSE:Factory checked in at 2026-08-21 16:56:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/clpeak (Old) and /work/SRC/openSUSE:Factory/.clpeak.new.1258 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "clpeak" Fri Aug 21 16:56:20 2026 rev:18 rq:1372634 version:2.1.2 Changes: -------- --- /work/SRC/openSUSE:Factory/clpeak/clpeak.changes 2026-08-19 18:01:13.860261392 +0200 +++ /work/SRC/openSUSE:Factory/.clpeak.new.1258/clpeak.changes 2026-08-21 16:57:48.151502138 +0200 @@ -1,0 +2,9 @@ +Thu Aug 20 18:40:38 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to 2.1.2: + * Keep machine-readable output locale-independent so XML + dumps, JSON/CSV exports and parsed values always use '.' + as the decimal separator, including under comma-decimal + locales (gh#krrishnarraj/clpeak#199). + +------------------------------------------------------------------- Old: ---- clpeak-2.1.1.tar.gz New: ---- clpeak-2.1.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ clpeak.spec ++++++ --- /var/tmp/diff_new_pack.g4YqbB/_old 2026-08-21 16:57:48.930529772 +0200 +++ /var/tmp/diff_new_pack.g4YqbB/_new 2026-08-21 16:57:48.932529843 +0200 @@ -18,7 +18,7 @@ Name: clpeak -Version: 2.1.1 +Version: 2.1.2 Release: 0 Summary: Find peak OpenCL capacities like bandwidth & compute # Legal-Review-Notice: upstream relicensed from the Unlicense to Apache-2.0 @@ -46,7 +46,7 @@ %prep %autosetup -p1 # GitHub archives have no .git, so git-describe is unavailable and -# version.cmake's hardcoded fallback is stale (still 2.0.16 in 2.1.1). +# version.cmake's hardcoded fallback is stale (still 2.0.16 in 2.1.2). # gh#krrishnarraj/clpeak#198 sed -i 's/set(CLPEAK_VERSION_FALLBACK ".*")/set(CLPEAK_VERSION_FALLBACK "%{version}")/' \ src/common/cmake/version.cmake ++++++ clpeak-2.1.1.tar.gz -> clpeak-2.1.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/.github/workflows/build.yml new/clpeak-2.1.2/.github/workflows/build.yml --- old/clpeak-2.1.1/.github/workflows/build.yml 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/.github/workflows/build.yml 2026-08-20 17:30:08.000000000 +0200 @@ -33,7 +33,6 @@ - name: Linux x64 runner: ubuntu-latest artifact: clpeak-linux-x86_64 - gui: true binary: build/clpeak suffix: "" cuda: false @@ -41,7 +40,6 @@ - name: Linux arm64 runner: ubuntu-24.04-arm artifact: clpeak-linux-arm64 - gui: false binary: build/clpeak suffix: "" cuda: false @@ -49,7 +47,6 @@ - name: Windows x64 runner: windows-latest artifact: clpeak-windows-x86_64 - gui: true binary: build/Release/clpeak.exe suffix: "" cuda: false @@ -57,7 +54,6 @@ - name: Windows arm64 runner: windows-11-arm artifact: clpeak-windows-arm64 - gui: false binary: build/Release/clpeak.exe suffix: "" cuda: false @@ -65,7 +61,6 @@ - name: macOS arm64 runner: macos-latest artifact: clpeak-macos-arm64 - gui: true binary: build/clpeak suffix: "" cuda: false @@ -73,7 +68,6 @@ - name: Linux x64 CUDA runner: ubuntu-latest artifact: clpeak-linux-x86_64-cuda - gui: true binary: build/clpeak suffix: cuda cuda: true @@ -81,7 +75,6 @@ - name: Linux arm64 CUDA runner: ubuntu-24.04-arm artifact: clpeak-linux-arm64-cuda - gui: false binary: build/clpeak suffix: cuda cuda: true @@ -89,7 +82,6 @@ - name: Windows x64 CUDA runner: windows-latest artifact: clpeak-windows-x86_64-cuda - gui: true binary: build/Release/clpeak.exe suffix: cuda cuda: true @@ -97,7 +89,6 @@ - name: Linux x64 ROCm runner: ubuntu-24.04 artifact: clpeak-linux-x86_64-rocm - gui: true binary: build/clpeak suffix: rocm cuda: false @@ -106,7 +97,6 @@ - name: Linux x64 oneAPI runner: ubuntu-latest artifact: clpeak-linux-x86_64-oneapi - gui: true binary: build/clpeak suffix: oneapi cuda: false @@ -129,18 +119,18 @@ # (GCC<=14 serialises the FMA accumulator chains, ~halving fp32/fp64). sudo apt-get install -y --no-install-recommends build-essential clang - # `flutter build linux` toolchain, GUI jobs only. + # `flutter build linux` toolchain. - name: Install GUI dependencies (Linux) - if: runner.os == 'Linux' && matrix.gui + if: runner.os == 'Linux' run: | sudo apt-get install -y --no-install-recommends \ ninja-build pkg-config libgtk-3-dev liblzma-dev - name: Set up Flutter - if: matrix.gui uses: subosito/flutter-action@v2 with: - channel: stable + channel: master + flutter-version: 3.47.1 cache: true - name: Install Vulkan SDK @@ -247,7 +237,7 @@ # is ad-hoc signed, so first launch still needs right-click -> Open until # a Developer ID identity is wired in here. - name: Package DMG (macOS) - if: runner.os == 'macOS' && matrix.gui + if: runner.os == 'macOS' run: cmake --build build --target clpeak-gui-dmg - name: Upload artifact @@ -262,7 +252,7 @@ # each download unpacks straight to the thing you wanted. (Release # assets are unaffected -- the release job attaches the raw files.) - name: Upload DMG artifact - if: runner.os == 'macOS' && matrix.gui + if: runner.os == 'macOS' uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact }}-dmg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/AGENTS.md new/clpeak-2.1.2/AGENTS.md --- old/clpeak-2.1.1/AGENTS.md 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/AGENTS.md 2026-08-20 17:30:08.000000000 +0200 @@ -60,9 +60,7 @@ - Each backend: `-DCLPEAK_ENABLE_VULKAN=OFF`, etc. - GUI: built automatically as `clpeak-gui` when the Flutter SDK is detected (disable with `-DCLPEAK_ENABLE_GUI=OFF`); bundle lands in `build/clpeak-gui/`. - Flutter's desktop SDK is x64-only on Linux/Windows, so those arm64 CI jobs - build CLI-only (`gui: false` in the workflow matrix). Mobile builds: see - `app/AGENTS.md`. + Mobile builds: see `app/AGENTS.md`. - All backend static libs are built PIC (`CMAKE_POSITION_INDEPENDENT_CODE`): they link into both `clpeak` and the `clpeak_ffi` shared library. - Packaging: `cpack -G ZIP` ships CLI + GUI in one archive — `bin/clpeak`, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/app/pubspec.yaml new/clpeak-2.1.2/app/pubspec.yaml --- old/clpeak-2.1.1/app/pubspec.yaml 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/app/pubspec.yaml 2026-08-20 17:30:08.000000000 +0200 @@ -3,7 +3,7 @@ publish_to: 'none' # versionName / versionCode -version: 2.1.0+32 +version: 2.1.2+33 environment: sdk: ^3.12.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/src/common/inventory.cpp new/clpeak-2.1.2/src/common/inventory.cpp --- old/clpeak-2.1.1/src/common/inventory.cpp 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/src/common/inventory.cpp 2026-08-20 17:30:08.000000000 +0200 @@ -1,5 +1,6 @@ #include <common/inventory.h> #include <common/common.h> +#include <locale> #include <ostream> #include <sstream> #include <string> @@ -36,6 +37,10 @@ std::string inventoryToJson(const std::vector<BackendInventory> &inv) { std::ostringstream os; + // Machine-readable interchange: JSON is locale-free, and the GUI decodes + // this with the host toolkit's locale already installed (see fmtFloat in + // src/ffi/logger_ffi.cpp). + os.imbue(std::locale::classic()); os << "{\"backends\":["; for (size_t i = 0; i < inv.size(); ++i) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/src/common/result_store.cpp new/clpeak-2.1.2/src/common/result_store.cpp --- old/clpeak-2.1.1/src/common/result_store.cpp 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/src/common/result_store.cpp 2026-08-20 17:30:08.000000000 +0200 @@ -5,6 +5,7 @@ #include <sstream> #include <iomanip> #include <iostream> +#include <locale> #include <cstring> // ---- Enum <-> string ------------------------------------------------------ @@ -109,13 +110,37 @@ return out; } +// Every number in every dump format goes through here, and every number read +// back comes through parseFloatC below. Both pin the classic locale on +// purpose: the GUI hosts these writers inside a toolkit that sets the process +// locale (GTK's gtk_init calls setlocale(LC_ALL, "")), and a comma decimal +// separator would produce files that are neither valid JSON nor readable by +// the loaders. The dump formats are machine-readable interchange, not +// user-facing text -- they are always '.' regardless of where clpeak runs. static std::string fmtValue(float v) { std::stringstream ss; + ss.imbue(std::locale::classic()); ss << std::fixed << std::setprecision(4) << v; return ss.str(); } +// Read a float written by fmtValue. Leading whitespace is skipped and +// trailing text ignored, so the caller can hand over the rest of a JSON line +// or an XML element body. Returns false (leaving `out` untouched) when the +// text does not start with a number -- std::stof's `consumed == 0` case, but +// without stof's dependence on the C locale's LC_NUMERIC. +static bool parseFloatC(const std::string &s, float &out) +{ + std::istringstream is(s); + is.imbue(std::locale::classic()); + float v = 0.0f; + if (!(is >> v)) + return false; + out = v; + return true; +} + // ---- JSON save ------------------------------------------------------------ // Self-describing wrapper: // {"format_version":2,"clpeak_version":"...","os":"...","entries":[ … ]} @@ -124,6 +149,7 @@ static void writeJson(const ResultStore &store, std::ostream &f, const DeviceInfoStore &devices) { + f.imbue(std::locale::classic()); f << "{\"format_version\":" << RESULT_FORMAT_VERSION << ",\"clpeak_version\":\"" << jsonEscape(CLPEAK_VERSION_STR) << "\"" << ",\"os\":\"" << jsonEscape(OS_NAME) << "\""; @@ -234,6 +260,7 @@ std::cerr << "clpeak: cannot open CSV output file: " << filename << "\n"; return false; } + f.imbue(std::locale::classic()); f << "format_version,backend,platform,device,driver,category,test,metric,unit,status,value,reason,display,description,metric_description\n"; for (const ResultEntry &e : store) { @@ -337,6 +364,8 @@ return false; } + f.imbue(std::locale::classic()); + // Rows are streamed in run order; props are looked up per run. std::map<std::string, const DeviceInfo *> deviceByKey; for (const DeviceInfo &d : devices) @@ -477,13 +506,8 @@ pos += needle.size(); while (pos < line.size() && line[pos] == ' ') pos++; if (pos >= line.size() || line[pos] == '"') return 0.0f; - try - { - size_t consumed = 0; - float v = std::stof(line.substr(pos), &consumed); - return (consumed > 0) ? v : 0.0f; - } - catch (...) { return 0.0f; } + float v = 0.0f; + return parseFloatC(line.substr(pos), v) ? v : 0.0f; } static int jsonExtractInt(const std::string &line, const std::string &key) @@ -726,13 +750,8 @@ e.status = statusFromString(fields[9]); if (e.status == ResultStatus::Ok) { - try - { - size_t consumed = 0; - e.value = std::stof(fields[10], &consumed); - if (consumed == 0) continue; - } - catch (...) { continue; } + if (!parseFloatC(fields[10], e.value)) + continue; } e.reason = fields[11]; if (fields.size() >= 13) @@ -908,8 +927,8 @@ continue; std::string content = xmlUnescape( t.substr(openEnd + 1, closePos - openEnd - 1)); - try { e.value = std::stof(content); } - catch (...) { continue; } + if (!parseFloatC(content, e.value)) + continue; } if (!e.backend.empty() && !e.test.empty() && !e.metric.empty()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/src/cpu/cpu_peak.cpp new/clpeak-2.1.2/src/cpu/cpu_peak.cpp --- old/clpeak-2.1.1/src/cpu/cpu_peak.cpp 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/src/cpu/cpu_peak.cpp 2026-08-20 17:30:08.000000000 +0200 @@ -6,8 +6,10 @@ #include <algorithm> #include <chrono> -#include <cstdio> +#include <iomanip> +#include <locale> #include <ostream> +#include <sstream> #include <string> CpuPeak::CpuPeak() {} @@ -26,14 +28,19 @@ targetTimeUs = opts.targetTimeUsCpu; } -// Human-readable byte size for the device property block. +// Human-readable byte size for the device property block. Streams pinned to +// the classic locale, not printf: this string is persisted in the dump files +// and the GUI runs with the host toolkit's locale set, which would otherwise +// write "8,0 GB" there but "8.0 GB" from the CLI on the same machine. static std::string fmtBytes(uint64_t b) { - char buf[64]; - if (b >= (1ull << 30)) std::snprintf(buf, sizeof(buf), "%.1f GB", b / (double)(1ull << 30)); - else if (b >= (1ull << 20)) std::snprintf(buf, sizeof(buf), "%.0f MB", b / (double)(1ull << 20)); - else std::snprintf(buf, sizeof(buf), "%.0f KB", b / (double)(1ull << 10)); - return buf; + std::ostringstream ss; + ss.imbue(std::locale::classic()); + ss << std::fixed; + if (b >= (1ull << 30)) ss << std::setprecision(1) << b / (double)(1ull << 30) << " GB"; + else if (b >= (1ull << 20)) ss << std::setprecision(0) << b / (double)(1ull << 20) << " MB"; + else ss << std::setprecision(0) << b / (double)(1ull << 10) << " KB"; + return ss.str(); } double CpuPeak::runWorkload(int nThreads, const Workload &body, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clpeak-2.1.1/src/ffi/logger_ffi.cpp new/clpeak-2.1.2/src/ffi/logger_ffi.cpp --- old/clpeak-2.1.1/src/ffi/logger_ffi.cpp 2026-08-18 19:08:27.000000000 +0200 +++ new/clpeak-2.1.2/src/ffi/logger_ffi.cpp 2026-08-20 17:30:08.000000000 +0200 @@ -3,9 +3,10 @@ #include <common/common.h> #include <common/result_store.h> -#include <cstdio> #include <cstdlib> #include <cstring> +#include <iomanip> +#include <locale> #include <sstream> namespace @@ -33,11 +34,19 @@ ss << ",\"" << key << "\":\"" << jsonEscape(value) << "\""; } +// JSON numbers are '.'-separated by definition, so this must not follow the +// process locale. It matters here more than anywhere else in clpeak: the GUI +// hosts this library inside a toolkit that sets the locale for us (GTK's +// gtk_init calls setlocale(LC_ALL, "")), so on a comma-decimal desktop a +// printf("%.4f") emitted `"value":1234,5678` -- malformed JSON that the Dart +// side dropped, leaving the live results view empty while the XML dump (which +// never went through the C locale) stayed correct. std::string fmtFloat(float v) { - char buf[32]; - std::snprintf(buf, sizeof(buf), "%.4f", v); - return buf; + std::ostringstream ss; + ss.imbue(std::locale::classic()); + ss << std::fixed << std::setprecision(4) << v; + return ss.str(); } } // namespace @@ -45,6 +54,7 @@ std::string ffiEventToJson(const LogEvent &e) { std::ostringstream ss; + ss.imbue(std::locale::classic()); // see fmtFloat -- the indices too ss << "{\"t\":\"" << kindTag(e.kind) << "\""; // Scope context — present on every scoped event.
