Skip to content

Conversation

@enum-class
Copy link
Owner

No description provided.

Signed-off-by: Saman Dehghan <samaan.dehghan@gmail.com>
#endif
.names_size = END_NAMES - START_NAMES,
.counters_delta = (uintptr_t)START_COUNTERS,
.names_delta = (uintptr_t)START_NAMES,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why (uintptr_t) is removed? On my side this does not compile with either GCC or Clang

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's focus on #2 , I just put this here as a record for a version before adding clang-11 to clang-13 support. ignore this PR.

@whentojump
Copy link
Collaborator

  1. What is this PR's purpose? #3 apparently is not the squashed version of #2. Creating more PRs is inconvenient for code review or tracking changes.

  2. I tested on x86 -- with or without rounding up num_counters/num_data , I can generate coverage reports from end to end successfully in either case. I cannot reproduce your warning

    llvm-profdata-19 merge cov.dat -o xen.profdata
    warning: cov.dat: invalid instrumentation profile data (file header is corrupt)
    error: no profile can be merged
    

    Why? Can you give a more detailed testing procedure so others can reproduce your results?

  3. During linking tons of warnings like below fly by:

    ld: warning: orphan section `__llvm_prf_names' from `prelink.o' being placed in section `__llvm_prf_names'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_data'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_data'
    

    Are you also seeing it or not?

@whentojump
Copy link
Collaborator

whentojump commented Oct 12, 2025

My steps of x86 testing, starting with a fresh Debian bookworm VM

  • I myself have several questions about Xen build and boot process (see ❓s). If you happen to know some of the answers please let me know
  • Running the below can successfully produce coverage reports without rounding up. See my changes on top of yours whentojump/xen@V3...whentojump:xen:V3-wentao
  • Can you create a documentation that has similar levels of detail (if not more) for your steps and hopefully we can reproduce and troubleshoot file header is corrupt?
## Dependencyies 

sudo apt install build-essential libncurses-dev flex bison \
kconfig-frontends-nox python3-dev acpica-tools uuid-dev pkgconf libglib2.0-dev \
libpixman-1-dev libyajl-dev python3-venv ninja-build \
lsb-release wget software-properties-common gnupg

wget https://apt.llvm.org/llvm.sh -O /tmp/llvm.sh
chmod +x /tmp/llvm.sh
sudo /tmp/llvm.sh 20
rm /tmp/llvm.sh

## Build Xen

# git clone git@github.com:enum-class/xen.git --branch V3 --depth=10 xen-source
git clone https://github.com/whentojump/xen.git --branch V3-wentao --depth=10 xen-source

cd xen-source

LLVM_DIR=/lib/llvm-20/bin

# ❓ I don't actually know whether we need them all or just CC
MAKE_FLAGS=(
    "CC=$LLVM_DIR/clang"
    # "LD=$LLVM_DIR/ld.lld"
    # "AR=$LLVM_DIR/llvm-ar"
    # "NM=$LLVM_DIR/llvm-nm"
    # "STRIP=$LLVM_DIR/llvm-strip"
    # "OBJCOPY=$LLVM_DIR/llvm-objcopy"
    # "OBJDUMP=$LLVM_DIR/llvm-objdump"
    # "READELF=$LLVM_DIR/llvm-readelf"
    # "HOSTCC=$LLVM_DIR/clang"
    # "HOSTCXX=$LLVM_DIR/clang++"
    # "HOSTAR=$LLVM_DIR/llvm-ar"
    # "HOSTLD=$LLVM_DIR/ld.lld"
)

# "--libdir=/lib/x86_64-linux-gnu/" makes life easier rather than the
# default /usr/local/lib and LD_LIBRARY_PATH hassle 
./configure --disable-xen --disable-docs --libdir=/lib/x86_64-linux-gnu/

# Build "tools" only with GNU
# ❓ This step builds a xen anyway under "tools/firmware/xen-dir/xen-root/xen". What is it?
make -j$(nproc) dist-tools
sudo make -j$(nproc) install-tools

# Build "xen" only with Clang/LLVM
make ${MAKE_FLAGS[@]} -C xen defconfig
pushd xen
kconfig-tweak -d LIVEPATCH
kconfig-tweak -e COVERAGE
popd
make ${MAKE_FLAGS[@]} -C xen olddefconfig
make ${MAKE_FLAGS[@]} -j$(nproc) efi-y= dist-xen
sudo make ${MAKE_FLAGS[@]} -j$(nproc) efi-y= install-xen

## Prepare for the next boot

# I don't have easy access to my VM's GRUB screen so this 
# is the only way for me to select Xen as boot target.
# It's somewhat good as it's noninteractive.
# But proceed with caution and carefully consider what string
# should be put here in your setup. E.g., run
# "sudo grep menuentry /boot/grub/grub.cfg | less"
# 
# sudo sed -i 's|GRUB_DEFAULT=0|GRUB_DEFAULT="Debian GNU/Linux, with Xen hypervisor"|' /etc/default/grub
#
sudo update-grub
sudo reboot

## After reboot 

# ❓ I don't know why only I need this (not you or Erkai :))). Otherwise I have 
# "xencall: error: Could not obtain handle on privileged command interface: No such file or directory
# xencov: opening xc interface: No such file or directory"
sudo systemctl start xencommons.service 
sudo systemctl enable xencommons.service 

sudo xencov read | tee >/dev/null default.profraw
file default.profraw
/lib/llvm-20/bin/llvm-profdata merge default.profraw -o default.profdata
file default.profdata
# Replace it with your path
XEN_SOURCE_DIR=/vagrant/xen-source/
TMP_REPORT_DIR=`mktemp -d`
/lib/llvm-20/bin/llvm-cov show \
  -instr-profile default.profdata \
  -output-dir $TMP_REPORT_DIR \
  -show-directory-coverage \
  -show-branches=count \
  -use-color=false \
  $XEN_SOURCE_DIR/xen/xen-syms
less $TMP_REPORT_DIR/index.txt
less $TMP_REPORT_DIR/coverage/$XEN_SOURCE_DIR/xen/common/coverage/llvm.c.txt
rm -r $TMP_REPORT_DIR

@whentojump
Copy link
Collaborator

One more note on linking, related to some of my previous comments/questions:

If LD is GNU linker (both your and my current way), there is a sensible delay around LD prelink.o but the time is still manageable on my side (~7min, Intel i9-14900k). Your earlier report of 6~7 hours frankly seems too much regardless of your CPU model. If it really has something to do with your hardware, please do use CloudLab https://github.com/xlab-uiuc/linux-mcdc/tree/cloudlab.

On the other hand, if I additionally use LLVM linker as well

MAKE_FLAGS=(
    "CC=$LLVM_DIR/clang"
    "LD=$LLVM_DIR/ld.lld"
)
  1. The linking time is much shorter (~30s, Intel i9-14900k)

  2. Also tons of warnings fly by my screen

    ld.lld: warning: prelink.o:(__llvm_prf_data) is being placed in '__llvm_prf_data'
    ld.lld: warning: prelink.o:(__llvm_prf_cnts) is being placed in '__llvm_prf_cnts'
    ld.lld: warning: prelink.o:(__llvm_prf_data) is being placed in '__llvm_prf_data'
    
  3. I cannot successfully run llvm-profdata this time

    $ /lib/llvm-20/bin/llvm-profdata merge default.profraw -o default.profdata
    warning: default.profraw: malformed instrumentation profile data: symbol name is empty
    error: no profile can be merged

@whentojump
Copy link
Collaborator

Allow me to cc @erkaii as well to see if he has some insights. But no obligation. Thanks!

@enum-class
Copy link
Owner Author

  1. What is this PR's purpose? #3 apparently is not the squashed version of #2. Creating more PRs is inconvenient for code review or tracking changes.

  2. I tested on x86 -- with or without rounding up num_counters/num_data , I can generate coverage reports from end to end successfully in either case. I cannot reproduce your warning

    llvm-profdata-19 merge cov.dat -o xen.profdata
    warning: cov.dat: invalid instrumentation profile data (file header is corrupt)
    error: no profile can be merged
    

    Why? Can you give a more detailed testing procedure so others can reproduce your results?

  3. During linking tons of warnings like below fly by:

    ld: warning: orphan section `__llvm_prf_names' from `prelink.o' being placed in section `__llvm_prf_names'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_data'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_data'
    

    Are you also seeing it or not?

I also see this warnings

@enum-class
Copy link
Owner Author

  1. What is this PR's purpose? #3 apparently is not the squashed version of #2. Creating more PRs is inconvenient for code review or tracking changes.

  2. I tested on x86 -- with or without rounding up num_counters/num_data , I can generate coverage reports from end to end successfully in either case. I cannot reproduce your warning

    llvm-profdata-19 merge cov.dat -o xen.profdata
    warning: cov.dat: invalid instrumentation profile data (file header is corrupt)
    error: no profile can be merged
    

    Why? Can you give a more detailed testing procedure so others can reproduce your results?

  3. During linking tons of warnings like below fly by:

    ld: warning: orphan section `__llvm_prf_names' from `prelink.o' being placed in section `__llvm_prf_names'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_empty]' from `prelink.o' being placed in section `__llvm_prf_data'
    ld: warning: orphan section `__llvm_prf_cnts[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_cnts'
    ld: warning: orphan section `__llvm_prf_data[__profc___bitmap_full]' from `prelink.o' being placed in section `__llvm_prf_data'
    

    Are you also seeing it or not?

I did not test without round-up on x86. I will test and let you know the result 👍

@enum-class
Copy link
Owner Author

One more note on linking, related to some of my previous comments/questions:

If LD is GNU linker (both your and my current way), there is a sensible delay around LD prelink.o but the time is still manageable on my side (7min, Intel i9-14900k). Your earlier report of 67 hours frankly seems too much regardless of your CPU model. If it really has something to do with your hardware, please do use CloudLab https://github.com/xlab-uiuc/linux-mcdc/tree/cloudlab.

On the other hand, if I additionally use LLVM linker as well

MAKE_FLAGS=(
    "CC=$LLVM_DIR/clang"
    "LD=$LLVM_DIR/ld.lld"
)
  1. The linking time is much shorter (~30s, Intel i9-14900k)
  2. Also tons of warnings fly by my screen
    ld.lld: warning: prelink.o:(__llvm_prf_data) is being placed in '__llvm_prf_data'
    ld.lld: warning: prelink.o:(__llvm_prf_cnts) is being placed in '__llvm_prf_cnts'
    ld.lld: warning: prelink.o:(__llvm_prf_data) is being placed in '__llvm_prf_data'
    
  3. I cannot successfully run llvm-profdata this time
    $ /lib/llvm-20/bin/llvm-profdata merge default.profraw -o default.profdata
    warning: default.profraw: malformed instrumentation profile data: symbol name is empty
    error: no profile can be merged

I didn't use llvm linker. My cpu is core-i5 4300U. CPUs are not comparable. And since linking is single-threaded most probably that's the reason of difference in time. I will try cloudlab and let you know the result

@enum-class enum-class marked this pull request as draft October 13, 2025 00:21
@whentojump
Copy link
Collaborator

I did not test without round-up on x86. I will test and let you know the result 👍

I see. It's possible that warning is specific to Arm, which I never ran. I can take a brief look

@enum-class
Copy link
Owner Author

enum-class commented Oct 13, 2025

3. I cannot successfully run llvm-profdata this time

Does it mean our code has some issue that with LLVM linker it doesn't work ?
It seems we need to test with different linker on different architecture. Also maybe we can test on 32bit cpus as well
?!

@whentojump
Copy link
Collaborator

Does it mean our code has some issue that with LLVM linker it doesn't work ?

In my own test, it looks like so. Please do verify.
I guess we need to figure out what is the assumption in Xen. I know in Linux make LLVM=1 means replacement of the full toolchain https://docs.kernel.org/kbuild/llvm.html but have no idea of Xen. Would you peek some Xen documentation CI instances etc. to find some evidence?

It seems we need to test with different linker on different architecture. Also maybe we can test on 32bit cpus as well
?!

I personally don't want to do that... I believe a lot of alignment in our code is assuming 64-bit. Let's focus on x86_64 and aarch64. For more, let's wait for opinions from the mailing list / Boeing.

@whentojump
Copy link
Collaborator

whentojump commented Oct 16, 2025

I just realize my "fast" builds all happened in an NFS directory; outside it, mine also becomes slow. The full reasoning behind it:

Expand/Collapse AI Chat

Q

I am debugging a flaky slow linking problem. For this or that reason, when I build in an NFS, it's fast; otherwise it's slow. I suspect some decisions in Makefiles are different.

The script is @build-both.sh . The relevant log is @chat.txt . This is the fast version. In the slow version, some steps around quoted Makefile seems the bottleneck. Analyze why the quoted Makefile part is not run in the fast run.

# xen/arch/x86/Makefile
extra-$(XEN_BUILD_PE) += efi.lds
ifeq ($(XEN_BUILD_PE),y)
$(TARGET).efi: $(objtree)/prelink.o $(note_file) $(obj)/efi.lds $(obj)/efi/relocs-dummy.o $(obj)/efi/mkreloc
ifeq ($(CONFIG_DEBUG_INFO),y)
	$(if $(filter --strip-debug,$(EFI_LDFLAGS)),echo,:) "Will strip debug info from $(@F)"
endif
	$(foreach base, $(VIRT_BASE) $(ALT_BASE), \
	          $(LD) $(call EFI_LDFLAGS,$(base)) -T $(obj)/efi.lds $< $(relocs-dummy) \
	                $(objtree)/common/symbols-dummy.o $(note_file_option) \
	                -o $(dot-target).$(base).0 &&) :
	$(MKRELOC) $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(dot-target).$(base).0) \
		> $(dot-target).0r.S
	$(NM) -pa --format=sysv $(dot-target).$(VIRT_BASE).0 \

A

I'll search the Xen x86 Makefiles to see how $(TARGET).efi gets invoked and under what conditions, and also scan the log for any references to building xen.efi.

[3 tools called]

I'll run a few quick searches in parallel to see how efi-y feeds into the build, to confirm whether $(TARGET).efi is only built conditionally, and to correlate with the log's FINDME marker and compile.h behavior.

[4 tools called]

I'll open the two relevant Makefiles to cite the exact lines that gate xen.efi and how XEN_BUILD_PE and efi-y control whether the heavy EFI link runs.

[2 tools called]

I checked the x86 build rules. The heavy EFI link recipe only runs when $(TARGET).efi is a prerequisite of $(TARGET) and when XEN_BUILD_PE=y. In your fast run, XEN_BUILD_PE=y is true, but $(TARGET) did not depend on $(TARGET).efi, so the quoted block never executed.

Key bits:

efi-y := $(shell if [ ! -r $(objtree)/include/xen/compile.h -o \
                      -O $(objtree)/include/xen/compile.h ]; then \
                         echo '$(TARGET).efi'; fi) \
         $(space)
...
$(TARGET): TMP = $(dot-target).elf32
$(TARGET): $(TARGET)-syms $(efi-y) $(obj)/boot/mkelf32
	$(obj)/boot/mkelf32 $(notes_phdrs) $(TARGET)-syms $(TMP) $(XEN_IMG_OFFSET)
extra-$(XEN_BUILD_PE) += efi.lds
ifeq ($(XEN_BUILD_PE),y)
$(TARGET).efi: $(objtree)/prelink.o $(note_file) $(obj)/efi.lds $(obj)/efi/relocs-dummy.o $(obj)/efi/mkreloc
	... big EFI link sequence ...
else
$(TARGET).efi: FORCE
	rm -f $@
	echo '$(if $(filter y,$(XEN_BUILD_EFI)),xen.efi generation,EFI support) disabled'
endif
EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names
LD_PE_check_cmd = $(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o $(efi-check).efi $(efi-check).o)
XEN_BUILD_PE := $(LD_PE_check_cmd)
...
$(info FINDME FINDME XEN_BUILD_PE=$(XEN_BUILD_PE))

What’s happening:

  • efi-y is computed at parse time via a shell test on include/xen/compile.h. It includes $(TARGET).efi only if the file is missing OR is owned by the effective user ([ -O file ]).
  • On your fast NFS run, include/xen/compile.h exists but is not reported as owned by your euid (common on NFS/root_squash or uid mapping), so the condition is false and efi-y is empty. Therefore $(TARGET) does not depend on $(TARGET).efi, and the heavy EFI link recipe is skipped.
  • XEN_BUILD_PE=y is confirmed in your log, so gating wasn’t the reason it skipped:
FINDME FINDME XEN_BUILD_PE=y
  UPD     include/xen/compile.h
  • You still see xen.efi get installed because it already existed from a previous build:
if [ -r xen.efi -a -n '/usr/lib64/efi' ]; then \
	... install xen.efi ...

Status: I inspected the Makefiles and your log. The EFI link block isn’t run in the fast (NFS) build because efi-y evaluates empty due to compile.h not being owned by your user on NFS, so xen doesn’t depend on xen.efi.

  • Root cause: efi-y ownership check (-O compile.h) fails on NFS, so $(TARGET).efi isn’t built as a prereq.
  • Effect: Skips the slow EFI link step; later install copies existing xen.efi if present.

Q2

What are the downside of not rebuilding EFI? In a non NFS directory, can I also skip it for faster testing?

A2

  • Downsides of not rebuilding xen.efi:

    • If you boot Xen via UEFI (hardware, OVMF/OVMF+QEMU, or any workflow that uses xen.efi), you’ll run a stale binary and not test your changes.
    • Version/build-id/debug-info and symbol maps for the EFI image won’t reflect your latest build, which can confuse debugging and packaging.
    • Changes affecting the PE/EFI link (linker flags, efi.lds, build-id handling, IBT/CF protections, etc.) won’t be exercised.
  • Yes, you can skip it locally for faster cycles when you don’t need the UEFI path:

    • Make the xen target not depend on xen.efi by emptying efi-y on the command line.
    • Also remove any pre-existing xen.efi so the install step doesn’t copy a stale file.

Example (fits your script that runs dist-xen):

make CC=/lib/llvm-20/bin/clang -C xen efi-y= dist-xen

If you want to ensure no stale xen.efi gets installed:

rm -f xen/xen.efi && make CC=/lib/llvm-20/bin/clang -C xen efi-y= dist-xen

Optional: you can also set XEN_BUILD_PE=n to ensure the EFI link recipe is disabled if it gets invoked indirectly, but the primary speedup comes from making efi-y empty so xen doesn’t depend on xen.efi.

  • When not to skip:
    • Any time you’re validating UEFI boot or anything that consumes the PE image, rebuild it.

Q3

If I'm going to boot Xen via GRUB, can I skip it?

A3

  • If GRUB loads Xen via multiboot/multiboot2 (entry points to xen/xen.gz), you can skip rebuilding xen.efi.
  • If GRUB is configured to use xen.efi (either multiboot2 /xen.efi ... or chainloader to xen.efi), don’t skip it.

Quick check: look at your GRUB stanza. If it says multiboot2 ... xen.gz, you’re fine to skip. If it references xen.efi or uses chainloader, don’t.

To skip in non-NFS builds for faster loops:

rm -f xen/xen.efi && make CC=/lib/llvm-20/bin/clang -C xen efi-y= dist-xen
  • efi-y= prevents xen from depending on xen.efi.
  • Removing any existing xen.efi avoids installing a stale EFI binary later.

Let me see if there is a general way to speed up all x86 builds.
Update: Ok I think the key is to add efi-y= in these two commands. I've also updated the steps in my above comment

make ${MAKE_FLAGS[@]} -j$(nproc) efi-y= dist-xen
sudo make ${MAKE_FLAGS[@]} -j$(nproc) efi-y= install-xen

The current measurement of make dist-xen is

  • VM atop CloudLab c6420: 18min32s
  • VM atop 14900k: 9min18s

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.

3 participants