Files
openwrt/target/linux/realtek/image/rt-loader/Makefile
T
Markus Stockhausen 0a70f32f4b realtek: rt-loader: use -O2 with selective LZMA inlining
Build rt-loader with -O2 and tune the LZMA decoder's inlining decisions
to balance code size and decompression performance.

The existing -O3 setting applies to all loader C sources. In the
standalone decoder comparison used to investigate this change, -O3
substantially increased the generated code size. Simply switching to
-O2 reduced that footprint, but left the frequently used rc_get_bit()
helper out of line, adding function-call and stack-access overhead
throughout range decoding.

Adjust the two helpers independently:

- Declare rc_get_bit() inline to encourage integration into its callers.
  This lets the compiler eliminate call overhead and optimise accesses
  to the range-coder state, probability values and decoded symbols.
- Mark rc_do_normalize() noinline to retain a shared implementation of
  the conditional normalisation path. This limits code duplication as
  the surrounding bit-decoding helpers are inlined.

Use the inline keyword rather than always_inline for rc_get_bit().
With the tested compiler, forcing this helper to inline provided no
additional benefit over the simpler declaration.

A standalone comparison with GCC 13.2.0 targeting MIPS32r2/34Kc used
the same synthetic 1 MiB LZMA stream, producing 4 MiB of output. A
generic single-issue in-order model with a 32 KiB instruction cache
and a 16 KiB data cache produced the following results:

- Original -O2: 4,960 bytes of decoder .text; 548,160,936 model cycles.
- Modified -O2: 4,960 bytes of decoder .text; 389,069,748 model cycles.
- Original -O3: 10,496 bytes of decoder .text; 336,140,240 model cycles.

In that setup, the modified -O2 decoder retains approximately 75% of
the cycle reduction achieved by -O3 while using 52.7% less code.
It requires 15.7% more model cycles than -O3. Compared with unmodified
-O2, it reduces model cycles by 29.0% without increasing code size.
All compared variants produced byte-identical output.

These figures describe the standalone decoder experiment, not measured
Realtek hardware performance. The experiment used -fno-pic and
-mno-abicalls; rt-loader retains -fpic and -mabicalls. Actual loader
size and boot-time effects therefore require validation with the
target build and hardware.

The patch changes the optimisation level for the whole loader and
the inlining policy of these two decoder helpers. It leaves the
decompression algorithm, bitstream format and error-handling logic
unchanged.

Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25813
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
2026-10-12 08:41:31 +02:00

141 lines
4.5 KiB
Makefile

# rt-loader make file
# (c) 2025 Markus Stockhausen
#
# This is the make file for the rt-loader (aka runtime or realtek loader). It tries to
# avoid copying files around where possible. Therefore it is controlled by the following
# input parameters
#
# KERNEL_IMG_IN: The filename of an LZMA compressed kernel. If given the loader
# and the kernel will be concatenated (piggy back loading).
# FLASH_ADDR: The kernel address in the ROM. If given, the loader will be
# created standalone and search a LZMA compressed uImage on the
# target device starting from this address.
# KERNEL_ADDR: The to-be-used kernel load address to which rt-loader will load
# the kernel and execute it. If not given, rt-loader will use its
# initial run address for this (which is the uImage load address
# when using U-boot images) For non-uImage, this uses an arbitrary
# load address which is independent of rt-loader's initial run
# address.
# KERNEL_IMG_OUT: The filename of the kernel image with the rt-loader prepended.
# If not given it will be created as image.bin into the BUILD_DIR.
# BUILD_DIR: The temporary build dir. If not given it will be set to "build".
#
# To add it into the OpenWrt toolchain just create the following new build commands
#
# define Build/rt-compress
# $(STAGING_DIR_HOST)/bin/xz --format=lzma -9 --stdout "$@" > "$@.new"
# mv "$@.new" "$@"
# endef
#
# define Build/rt-loader-piggy-back
# $(MAKE) all clean -C rt-loader CROSS_COMPILE="$(TARGET_CROSS)" \
# KERNEL_IMG_IN="$@" KERNEL_IMG_OUT="$@.new" BUILD_DIR="$@.build"
# mv "$@.new" "$@"
# endef
#
# define Build/rt-loader-non-uImage
# $(MAKE) all clean -C rt-loader CROSS_COMPILE="$(TARGET_CROSS)" \
# KERNEL_ADDR="$(KERNEL_LOADADDR)" KERNEL_IMG_IN="$@" \
# KERNEL_IMG_OUT="$@.new" BUILD_DIR="$@.build"
# mv "$@.new" "$@"
#
# define Build/rt-loader-standalone
# $(MAKE) all clean -C rt-loader CROSS_COMPILE="$(TARGET_CROSS)" \
# FLASH_ADDR=$(FLASH_ADDR) KERNEL_IMG_OUT="$@.new" BUILD_DIR="$@.build"
# mv "$@.new" "$@"
# endef
#
# Finally use them in new kernel build recipes. E.g. as all-in-one self extracting uImage.
#
# define Device/uimage-rt-loader
# KERNEL/rt-loader := kernel-bin | append-dtb | rt-compress | rt-loader-piggy-back
# KERNEL := $$(KERNEL/rt-loader) | uImage none
# KERNEL_INITRAMFS := $$(KERNEL/rt-loader) | uImage none
# endef
#
# Or as direct startable standlone version plus a kernel uImage
#
# define Device/rt-loader-uimage
# FLASH_ADDR := 0xb4000000
# KERNEL/rt-loader := rt-loader-standalone
# KERNEL := kernel-bin | append-dtb | rt-compress | uImage lzma
# endef
#
FLASH_ADDR_NONE := 0x0
FLASH_ADDR ?= $(FLASH_ADDR_NONE)
KERNEL_ADDR_NONE := 0x0
KERNEL_ADDR ?= $(KERNEL_ADDR_NONE)
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
CFLAGS = -fpic -mabicalls -O2 -fno-builtin-printf -Iinclude
CFLAGS += -DFLASH_ADDR=$(FLASH_ADDR)
CFLAGS += -DKERNEL_ADDR=$(KERNEL_ADDR)
ASFLAGS = -fpic -msoft-float -Iinclude
LDFLAGS = -static -nostdlib -T linker/linker.ld --no-warn-mismatch
O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
SOURCES = src/startup.S src/main.c src/board.c src/memory.c src/unlzma.c
BUILD_DIR ?= build
IMAGE_OBJ := $(BUILD_DIR)/image.o
IMAGE_ELF := $(BUILD_DIR)/image.elf
KERNEL_IMG_NONE := $(BUILD_DIR)/empty_kernel.bin
KERNEL_IMG_IN ?= $(KERNEL_IMG_NONE)
KERNEL_IMG_OUT ?= $(BUILD_DIR)/image.bin
OBJECTS_C = $(filter %.c,$(SOURCES))
OBJECTS_S = $(filter %.S,$(SOURCES))
OBJECTS := $(OBJECTS_S:.S=.o) $(OBJECTS_C:.c=.o)
OBJECTS := $(patsubst %.o, $(BUILD_DIR)/%.o, $(OBJECTS)) $(IMAGE_OBJ)
ifneq ($(MAKECMDGOALS),clean)
ifeq ($(KERNEL_IMG_IN)$(FLASH_ADDR),$(KERNEL_IMG_NONE)$(FLASH_ADDR_NONE))
$(error Set either KERNEL_IMG_IN or FLASH_ADDR)
else ifneq ($(FLASH_ADDR),$(FLASH_ADDR_NONE))
$(info Create standalone rt-loader, loading uimage from address $(FLASH_ADDR))
else
$(info Create piggy backed rt-loader, loading appended kernel binary "$(KERNEL_IMG_IN)")
endif
endif
all: $(KERNEL_IMG_OUT)
install:
$(BUILD_DIR)/%.o : %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_DIR)/%.o : %.S
@mkdir -p $(dir $@)
$(CC) $(ASFLAGS) -c -o $@ $<
$(IMAGE_OBJ): $(KERNEL_IMG_IN)
$(OBJCOPY) -I binary -O $(O_FORMAT) --rename-section .data=.kernel $< $@
$(IMAGE_ELF): $(OBJECTS)
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
$(KERNEL_IMG_OUT): $(IMAGE_ELF)
$(OBJCOPY) -O binary $< $@
$(KERNEL_IMG_IN):
@mkdir -p $(dir $@)
@echo "DUMMY-KERNEL-IMAGE" > $@
clean:
rm -rf $(BUILD_DIR)/