Skip to content

Conversation

@XueSongTap
Copy link
Contributor

Problem Description

When Google Benchmark runs in a WebAssembly environment, especially when compiled with Emscripten's -s FILESYSTEM=0 flag (which disables filesystem support), the program aborts when trying to access /sys/devices/system/cpu/cpu0/cache/ to retrieve CPU cache information.

This happens because the current implementation defaults to calling GetCacheSizesFromKVFS() on non-Windows/macOS/QNX/QURT platforms, a function that relies on filesystem access, which is not available in WebAssembly when the filesystem is disabled.

Solution

This PR modifies the GetCacheSizes() function in src/sysinfo.cc to detect Emscripten environments and return an empty cache info vector when running in WebAssembly, avoiding access to a non-existent filesystem.

The change is minimal, simply adding detection for the EMSCRIPTEN macro and merging it with the QURT OS handling, as both return empty cache information.

Related Issue

Fixes #1952

@google-cla
Copy link

google-cla bot commented Mar 24, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@XueSongTap
Copy link
Contributor Author

self test:

yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ emcc -O2 test_benchmark.cpp -o test_with_fs.js -I../include -L./src -lbenchmark
cache:INFO: generating system asset: symbol_lists/4ecc501da4e0b22aa538e28f5ac2b2f25c24ad56.json... (this will be cached in "/home/yxc/code/2503/emsdk/upstream/emscripten/cache/symbol_lists/4ecc501da4e0b22aa538e28f5ac2b2f25c24ad56.json" for subsequent builds)
cache:INFO:  - ok
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ emcc -O2 test_benchmark.cpp -o test_without_fs.js -I../include -L./src -lbenchmark -s FILESYSTEM=0
cache:INFO: generating system asset: symbol_lists/9e2ecc3f9ddd9359bfd85a70e497ee587e11349b.json... (this will be cached in "/home/yxc/code/2503/emsdk/upstream/emscripten/cache/symbol_lists/9e2ecc3f9ddd9359bfd85a70e497ee587e11349b.json" for subsequent builds)
cache:INFO:  - ok
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ node test_without_fs.js
***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect.
2025-03-25T00:08:43+08:00
Running /home/yxc/code/2503/benchmark_yxc/build_em/test_without_fs.js
Run on (1 X 999.986 MHz CPU )
***WARNING*** Library was built as DEBUG. Timings may be affected.
-------------------------------------------------------
Benchmark             Time             CPU   Iterations
-------------------------------------------------------
BM_EmptyLoop      0.000 ns        0.000 ns   1000000000000
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ node test_with_fs.js
***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect.
2025-03-25T00:08:57+08:00
Running /home/yxc/code/2503/benchmark_yxc/build_em/test_with_fs.js
Run on (1 X 999.99 MHz CPU )
***WARNING*** Library was built as DEBUG. Timings may be affected.
-------------------------------------------------------
Benchmark             Time             CPU   Iterations
-------------------------------------------------------
BM_EmptyLoop      0.000 ns        0.000 ns   1000000000000
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ cat test_benchmark.cpp
#include <benchmark/benchmark.h>

static void BM_EmptyLoop(benchmark::State& state) {
  for (auto _ : state) {

  }
}
BENCHMARK(BM_EmptyLoop);

BENCHMARK_MAIN();yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$

@XueSongTap
Copy link
Contributor Author

sek test

yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ emcc -O2 test_benchmark.cpp -o test_with_fs.js -I../include -L./src -lbenchmark
cache:INFO: generating system asset: symbol_lists/4ecc501da4e0b22aa538e28f5ac2b2f25c24ad56.json... (this will be cached in "/home/yxc/code/2503/emsdk/upstream/emscripten/cache/symbol_lists/4ecc501da4e0b22aa538e28f5ac2b2f25c24ad56.json" for subsequent builds)
cache:INFO:  - ok
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ emcc -O2 test_benchmark.cpp -o test_without_fs.js -I../include -L./src -lbenchmark -s FILESYSTEM=0
cache:INFO: generating system asset: symbol_lists/9e2ecc3f9ddd9359bfd85a70e497ee587e11349b.json... (this will be cached in "/home/yxc/code/2503/emsdk/upstream/emscripten/cache/symbol_lists/9e2ecc3f9ddd9359bfd85a70e497ee587e11349b.json" for subsequent builds)
cache:INFO:  - ok
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ node test_without_fs.js
***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect.
2025-03-25T00:08:43+08:00
Running /home/yxc/code/2503/benchmark_yxc/build_em/test_without_fs.js
Run on (1 X 999.986 MHz CPU )
***WARNING*** Library was built as DEBUG. Timings may be affected.
-------------------------------------------------------
Benchmark             Time             CPU   Iterations
-------------------------------------------------------
BM_EmptyLoop      0.000 ns        0.000 ns   1000000000000
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ node test_with_fs.js
***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect.
2025-03-25T00:08:57+08:00
Running /home/yxc/code/2503/benchmark_yxc/build_em/test_with_fs.js
Run on (1 X 999.99 MHz CPU )
***WARNING*** Library was built as DEBUG. Timings may be affected.
-------------------------------------------------------
Benchmark             Time             CPU   Iterations
-------------------------------------------------------
BM_EmptyLoop      0.000 ns        0.000 ns   1000000000000
yxc@yxc-MS-7B89:~/code/2503/benchmark_yxc/build_em$ cat test_benchmark.cpp
#include <benchmark/benchmark.h>

static void BM_EmptyLoop(benchmark::State& state) {
  for (auto _ : state) {

  }
}
BENCHMARK(BM_EmptyLoop);

BENCHMARK_MAIN();

@LebedevRI
Copy link
Collaborator

This does seem reasonable, but i have a question: is there any way to know
if the code is being compiled with filesystem support or not?
Can you dump the macros that the compiler sets in both modes, and post here?

https://stackoverflow.com/questions/2224334/gcc-dump-preprocessor-defines
https://stackoverflow.com/questions/4548702/whats-the-equivalent-of-cpp-dd-for-clang

@XueSongTap
Copy link
Contributor Author

@LebedevRI I've investigated the preprocessor macros between builds with and without filesystem support:

yxc@yxc-MS-7B89:~/code/2503/emsdk$ echo | emcc -dM -E - > with_fs.txt
yxc@yxc-MS-7B89:~/code/2503/emsdk$ echo | emcc -dM -E -s FILESYSTEM=0 - > without_fs.txt
emcc: warning: linker setting ignored during compilation: 'FILESYSTEM' [-Wunused-command-line-argument]
yxc@yxc-MS-7B89:~/code/2503/emsdk$ diff with_fs.txt without_fs.txt
yxc@yxc-MS-7B89:~/code/2503/emsdk$

I received this warning: emcc: warning: linker setting ignored during compilation: 'FILESYSTEM' [-Wunused-command-line-argument]

This confirms that -s FILESYSTEM=0 is a linker option rather than a preprocessor definition. During preprocessing, this option is ignored, so there's no specific preprocessor macro that can be used to detect filesystem support.

Therefore, using #ifdef EMSCRIPTEN appears to be the most reliable approach, as there's no more specific macro available to detect filesystem support status. The filesystem options are handled at link time rather than compile time in Emscripten.

@LebedevRI
Copy link
Collaborator

That's unfortunate. Is there some emscripten-native way to query CPU cache properties?

@LebedevRI
Copy link
Collaborator

That's unfortunate. Is there some emscripten-native way to query CPU cache properties?

@XueSongTap

@XueSongTap
Copy link
Contributor Author

After researching, I found that Emscripten doesn't provide a native API to query CPU cache properties, such as cache size, levels, or associativity. This limitation arises because WebAssembly (Wasm), the target output of Emscripten, operates in a sandboxed environment within the browser. This sandboxing restricts access to low-level hardware details, including CPU cache information, for security and portability reasons.

Emscripten's public API, as documented in the official reference, does not include functions for retrieving CPU cache properties. Additionally, the Emscripten runtime environment documentation highlights the abstraction from system-specific details, which further limits access to hardware-level information. ([Emscripten][1], [Emscripten][2])

Therefore, if benchmark requires detailed knowledge of CPU cache properties, we may need to consider alternative approaches.

@LebedevRI
Copy link
Collaborator

LebedevRI commented May 2, 2025

After researching

Thank you!

, I found that Emscripten doesn't provide a native API to query CPU cache properties, such as cache size, levels, or associativity. This limitation arises because WebAssembly (Wasm), the target output of Emscripten, operates in a sandboxed environment within the browser. This sandboxing restricts access to low-level hardware details, including CPU cache information, for security and portability reasons.

Emscripten's public API, as documented in the official reference, does not include functions for retrieving CPU cache properties. Additionally, the Emscripten runtime environment documentation highlights the abstraction from system-specific details, which further limits access to hardware-level information. ([Emscripten][1], [Emscripten][2])

Therefore, if benchmark requires detailed knowledge of CPU cache properties, we may need to consider alternative approaches.

I don't believe that it //requires// such knowledge,
but it provides such knowledge via public interface when avaliable,
and thus there are surely microbenchmarks out there
that themselves expect that info to be always provided.
(But obviously, a set of such benchmarks, and of the benchmarks
that are going to be run on WASM, is likely largely non-intersecting.)

Personally, i think a bug should be filed against Emscripten: it should set a define when in -s FILESYSTEM=0 mode.
@dmah42 thoughts? Should we just merge this as is?

@dmah42
Copy link
Member

dmah42 commented May 19, 2025

yeah i'm fine with this being merged. it's not ideal, but we're working around a platform and increasing usability.

@dmah42 dmah42 merged commit 3231850 into google:main May 19, 2025
84 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] Enable running benchmarks in WebAssembly without filesystem

3 participants