Wasm module defined ___ globals which exceeds the maximum number allowed 200

Hi @ktimam, so you don’t need me to try and get a backtrace anymore?

1 Like

Thanks a lot @abk . All is good now.

1 Like

Hi @abk ,

Would it be possible to update ic-wasm shrink, so it first removes the exports of globals, and then does the shrink?


The background is that I am at it again with hitting the globals limit in a C++ project, and even though I have found a good solution that I can implement in icpp-pro, it would be more elegant/convenient if it is implemented directly in ic-wasm.

This is what I have done so far:

  • I have a wasm file created from C++ that has 1003 globals
  • When I first remove the exports of globals, and then use ic-wasm shrink, it reduces to 144 globals that are actually used.
    • NOTE: Ulan explained above that (1) it is OK to remove all exports of globals, and (2) if a global is exported, ic-wasm shrink does NOT remove it, even if it is actually unused.
  • I did an exhaustive investigation of all options provided by the Clang++ & wasm-ld tool chain to check if I can avoid unused globals from being exported and concluded that it is NOT possible.
  • I then investigated available tools to remove the exported globals from the wasm before running ic-wasm shrink. I found a nice & simple approach that would easily fit into icpp-pro, which is a python based cli, by using this python function based on binaryan.py
"""
binaryen.py            :  https://github.com/jonathanharg/binaryen.py/tree/main
Binaryen C header file: https://github.com/WebAssembly/binaryen/blob/main/src/binaryen-c.h

Reference the Binaryen header file to understand how to use Binaryen. 
This package makes no significant changes to how Binaryen is used. 
The majority of the work this module does is interoperating between 
C and Python and creating more pythonic classes for Modules, Expressions and Functions.

You can still call any missing functions that haven't been implemented by 
the wrapper yet by calling them directly. To do this use 
binaryen.lib.BinaryenFullFunctionName() and call the full function name 
as described in the Binaryen header file.

"""
import binaryen
from binaryen import ffi, lib

##########################################################################
# Load a WebAssembly binary
wasm_bytes = open("build/llama_cpp_orig.wasm", "rb").read()

# Convert the binary data to a C data type that Binaryen can understand
wasm_ptr = ffi.new("char[]", wasm_bytes)
wasm_size = len(wasm_bytes)

# Use Binaryen's C API to read the module from the binary
module_ref = lib.BinaryenModuleRead(wasm_ptr, wasm_size)

# Wrap the module_ref in a Python object so you can use it with the rest of binaryen.py's API
module = binaryen.Module()
module.ref = module_ref

##########################################################################
# Remove all exports of globals

# Constant value for BinaryenExternalKindGlobal
BinaryenExternalKindGlobal = 3

# Iterate over the exports and collect the names of all global exports
exports_to_remove = []
for i in range(lib.BinaryenGetNumExports(module.ref)):
    export_ref = lib.BinaryenGetExportByIndex(module.ref, i)
    if lib.BinaryenExportGetKind(export_ref) == BinaryenExternalKindGlobal:
        export_name = ffi.string(lib.BinaryenExportGetName(export_ref)).decode('utf-8')
        exports_to_remove.append(export_name)

# Remove the global exports
for export_name in exports_to_remove:
    lib.BinaryenRemoveExport(module.ref, export_name.encode('utf-8'))

# Write the modified module back to a file
with open("build/llama_cpp_orig_stripped.wasm", "wb") as f:
    f.write(module.emit_binary())

  • If I now apply ic-wasm shrink to the stripped wasm, it deploys without a problem

However, before implementing this into icpp-pro, which would introduce another dependency, I like to ask if it would be possible to update ic-wasm to do the same and strip the exports of globals before shrinking it.

Looking forward to your feedback.

Yes I think this would be a reasonable change. It would probably be faster if you were willing to open a PR yourself. The main code change would be here where you can remove all the global exports from the walrus::Module.

1 Like

@abk, thanks for the feedback.

I actually found a method that fits better within icpp-pro, which is a python based cli.

It turns out that there is a python package, binaryen.py, that delivers binaryen as python wheels via PyPI for all supported platforms.

I can just install that with pip install binaryen.py, and I wrote a simple script that first removes the export of globals and then does an optimization at level 0. Amazingly, the number of globals went from 1003 to 1.

I am going that route for now.

1 Like