Home > other >  Where is source code for "cold" functions located in glibc?
Where is source code for "cold" functions located in glibc?

Time:05-17

I have a hello world program in C:

#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

Compile it gcc -static hello.c -o hello

In readelf -a --wide hello I found some functions with cold postfix

__assert_fail_base.cold
_nl_load_domain.cold
_IO_new_fclose.cold
_IO_fflush.cold
_IO_puts.cold
_IO_wfile_underflow.cold
_IO_new_file_underflow.cold
_IO_fputs.cold
_IO_fwrite.cold
_IO_getdelim.cold
__printf_fp_l.cold
__printf_fphex.cold
read_encoded_value_with_base.cold
base_of_encoded_value.cold
execute_cfa_program.cold
uw_frame_state_for.cold
uw_install_context_1.cold
execute_stack_op.cold
uw_update_context_1.cold
uw_init_context_1.cold
uw_update_context.cold
_Unwind_RaiseException_Phase2.cold
_Unwind_GetGR.cold
_Unwind_SetGR.cold
_Unwind_Resume.cold
_Unwind_Resume_or_Rethrow.cold
size_of_encoded_value.cold
base_from_object.cold
base_from_cb_data.cold
read_encoded_value_with_base.cold
_Unwind_IteratePhdrCallback.cold
search_object.cold
base_of_encoded_value.cold
read_encoded_value_with_base.cold

From here:

The cold attribute on functions is used to inform the compiler that the function is unlikely to be executed. The function is optimized for size rather than speed and on many targets it is placed into a special subsection of the text section so all cold functions appear close together, improving code locality of non-cold parts of program. The paths leading to calls of cold functions within code are marked as unlikely by the branch prediction mechanism. It is thus useful to mark functions used to handle unlikely conditions, such as perror, as cold to improve optimization of hot functions that do call marked functions in rare occasions.

When profile feedback is available, via -fprofile-use, cold functions are automatically detected and this attribute is ignored.

According that I download glibc and switch to commit 160f6c36a374841ee6e2bf2ee0ba05b70634978e which points to my version git rev-list -n 1 $(git tag | grep 2.31-0ubuntu9.7), but after all of this actions I cannot find any functions from above marked with the cold atribute.

I know that glibc generates some of the syscalls, but I don't find any interesting functions for me in glibc/sysdeps/unix/syscalls.list.

I also extracted cold functions from libc.a:

cd /usr/lib/x86_64-linux-gnu/
readelf -a --wide libc.a | egrep '\.cold' | awk '{print $NF}' > libc.a.cold

and compared them with readelf -a --wide hello | egrep '\.cold' | awk '{print $NF}' > hello.readelf:

grep -f libc.a.cold hello.readelf

These are the matched functions:

__assert_fail_base.cold
_nl_load_domain.cold
_IO_new_fclose.cold
_IO_fflush.cold
_IO_puts.cold
_IO_wfile_underflow.cold
_IO_new_file_underflow.cold
_IO_fputs.cold
_IO_fwrite.cold
_IO_getdelim.cold
__printf_fp_l.cold
__printf_fphex.cold

And with grep -f libc.a.cold hello.readelf -v I found the unmatched functions:

read_encoded_value_with_base.cold
base_of_encoded_value.cold
execute_cfa_program.cold
uw_frame_state_for.cold
uw_install_context_1.cold
execute_stack_op.cold
uw_update_context_1.cold
uw_init_context_1.cold
uw_update_context.cold
_Unwind_RaiseException_Phase2.cold
_Unwind_GetGR.cold
_Unwind_SetGR.cold
_Unwind_Resume.cold
_Unwind_Resume_or_Rethrow.cold
size_of_encoded_value.cold
base_from_object.cold
base_from_cb_data.cold
read_encoded_value_with_base.cold
_Unwind_IteratePhdrCallback.cold
search_object.cold
base_of_encoded_value.cold
read_encoded_value_with_base.cold

Questions:

  1. Can someone please help me to figure out where I can find a source code of cold functions?
  2. Where is the source code of unmatched functions from libc.a and the hello binary located, and from which library are they loaded?

Versions:

  • glibc: ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31

  • gcc: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0

  • Linux distro:

    DISTRIB_ID=Ubuntu
    DISTRIB_RELEASE=20.04
    DISTRIB_CODENAME=focal
    DISTRIB_DESCRIPTION="Ubuntu 20.04.4 LTS"
    
  • Kernel: 5.13.0-41-generic

CodePudding user response:

Functions do not necessarily have to be marked as cold using __attribute__((cold)) in order for GCC to realize that they are "cold". GCC can and will do this by itself when the appropriate optimizations are enabled.

In particular, quoting from GCC's optimizations doc:

-freorder-blocks-and-partition

In addition to reordering basic blocks in the compiled function, in order to reduce number of taken branches, partitions hot and cold basic blocks into separate sections of the assembly and .o files, to improve paging and cache locality performance.

This optimization is automatically turned off in the presence of exception handling or unwind tables (on targets using setjump/longjump or target specific scheme), for linkonce sections, for functions with a user-defined section attribute and on any architecture that does not support named sections. When -fsplit-stack is used this option is not enabled by default (to avoid linker errors), but may be enabled explicitly (if using a working linker).

Enabled for x86 at levels -O2, -O3, -Os.

As you can see, this optimization is enabled by default at -O2, -O3 and -Os.

A simple example of when such an automatic optimization could be applied would be a situation like the following:

if (__builtin_expect(<condition>, 1)) {
    some_function(123);
} else {
    some_function(456);
}

GCC can split some_function into some_function and some_function.cold, simplifying the internal logic of the two functions. So in your case, those .cold functions you see in the compiled binary are not actually defined in the source code as such, but rather produced by GCC automatically.

CodePudding user response:

where I can find a source code of cold functions?

In glibc source code.

I cannot find any functions from above marked with cold atribute

That is very odd, simple grep -R is enough, but you might be interested in code indexing - clangd, GLOBAL tags, ctags, etc. You can interest yourself in the_silver_searcher for faster grep.

$ git clone git://git.launchpad.net/ubuntu/ source/glibc
Cloning into 'glibc'...
...
$ cd glibc/
$ grep -R --include '*.c' __assert_fail_base
assert/assert.c:__assert_fail_base (const char *fmt, const char *assertion, const char *file,
assert/assert.c:  __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"),
assert/assert-perr.c:  __assert_fail_base (_("%s%s%s:%u: %s%sUnexpected error: %s.\n%n"),

So __assert_fail_base is defined in assert/assert.c. You can repeat the process for every function.

But it's much simpler to just type the function in google or find the project on github and search there. And there is also https://code.woboq.org/ , which makes the task just trivial.

Where is located source code of unmatched functions from libc.a and hello binary and from which library they loads?

That looks like inside libgcc and the Unwind most probably in gcc libstdc .

  • Related