bsd-thread-time-example/README.md

3.5 KiB

Example: Getting run time of a thread in FreeBSD

I wrote this example app when researching how to find the run time of a specific thread. The OpenJDK garbage collector implementations as well as other parts of the OpenJDK needs this information. Since I had written it, I figured I might as well share it with the community. Perhaps some will find it useful.

The code demonstrated three ways of getting the run time of a thread other than the requesting thread, and one way of getting the run time of the current thread.

Getting run time via clock_gettime(2)

The system function clock_gettime(2) will return a struct timespec representing the current time of a given clock. We can obtain a clock that holds the total run time of a thread by calling pthread_getcpuclockid(3).

This is the sum of the user and sys time of the given thread with nanosecond precision.

See fast_cpu_time.cpp for an example of using this method.

Getting run time via libprocstat(3)

Using the functions provided by libprocstat(3) we can obtain the separate user and sys times for a thread with microsecond precision. This involves first opening a procstat handle (struct procstat *) using procstat_open_sysctl(3), querying the process info for all threads in the process using procstat_getprocs(3), and the and iterating through the returned array to find requested thread.

The call to procstat_getprocs(3) will dynamically allocate the memory for the returned array, which then has to be freed using procstat_freeprocs(3) after use. Finally the procstat handle must be freed using procstat_close(3).

In addition this method requires that we link with libprocstat(3).

The returned data is an array of struct kinfo_proc structures, that contains a field of type struct rusage, which again contains a struct timeval for the threads user time and one for the system time. These have microsecond precision.

To locate the requested thread we need the kernel thread id of the thread. We can obtain this by calling pthread_getthreadid_np(3), but only from the thread itself. To be able to use it from another thread, the thread id must be saved somewhere accessible. In this example I just use a global variable for illustration.

See procstat_cpu_time.cpp for an example using this method.

Getting run time via sysctl(3)

This is very similar to the libprocstat method above, but don't require linking with a library, and uses memory allocated by the caller rather than allocating it dynaically for you. This allows for using static preallocated memory if needed.

While the KERN_PROC_INC_THREAD modifier flag for KERN_PROC_PID is not documented in the sysctl(3) man page, it works the same as for the procstat call.

See syscall_cpu_time.cpp for an example of using this method.

Getting run time vis getrusage(2)

This method is pretty straight forward, but will only get the run time for the calling thread. It has the same microsecond precision that both the libprocstat and sysctl methods above has.

It also avoids the need for dynamic allocation as the caller provides a buffer of type struct rusage that is filled with the data.

See the code for the thread itself in main.cpp for an example of using this method.

License

Copyright (c) 2025 The FreeBSD Foundation
Copyright (c) 2025 Eilertsens Kodeknekkeri

SPDX-License-Identifier: BSD-2-Clause

This code is shared under a BSD 2-Clause license. See the included license for details.