• Daniel Bristot de Oliveira's avatar
    tracing/timerlat: Add user-space interface · e88ed227
    Daniel Bristot de Oliveira authored
    Going a step further, we propose a way to use any user-space
    workload as the task waiting for the timerlat timer. This is done
    via a per-CPU file named osnoise/cpu$id/timerlat_fd file.
    
    The tracef_fd allows a task to open at a time. When a task reads
    the file, the timerlat timer is armed for future osnoise/timerlat_period_us
    time. When the timer fires, it prints the IRQ latency and
    wakes up the user-space thread waiting in the timerlat_fd.
    
    The thread then starts to run, executes the timerlat measurement, prints
    the thread scheduling latency and returns to user-space.
    
    When the thread rereads the timerlat_fd, the tracer will print the
    user-ret(urn) latency, which is an additional metric.
    
    This additional metric is also traced by the tracer and can be used, for
    example of measuring the context switch overhead from kernel-to-user and
    user-to-kernel, or the response time for an arbitrary execution in
    user-space.
    
    The tracer supports one thread per CPU, the thread must be pinned to
    the CPU, and it cannot migrate while holding the timerlat_fd. The reason
    is that the tracer is per CPU (nothing prohibits the tracer from
    allowing migrations in the future). The tracer monitors the migration
    of the thread and disables the tracer if detected.
    
    The timerlat_fd is only available for opening/reading when timerlat
    tracer is enabled, and NO_OSNOISE_WORKLOAD is set.
    
    The simplest way to activate this feature from user-space is:
    
     -------------------------------- %< -----------------------------------
     int main(void)
     {
    	char buffer[1024];
    	int timerlat_fd;
    	int retval;
    	long cpu = 0;	/* place in CPU 0 */
    	cpu_set_t set;
    
    	CPU_ZERO(&set);
    	CPU_SET(cpu, &set);
    
    	if (sched_setaffinity(gettid(), sizeof(set), &set) == -1)
    		return 1;
    
    	snprintf(buffer, sizeof(buffer),
    		"/sys/kernel/tracing/osnoise/per_cpu/cpu%ld/timerlat_fd",
    		cpu);
    
    	timerlat_fd = open(buffer, O_RDONLY);
    	if (timerlat_fd < 0) {
    		printf("error opening %s: %s\n", buffer, strerror(errno));
    		exit(1);
    	}
    
    	for (;;) {
    		retval = read(timerlat_fd, buffer, 1024);
    		if (retval < 0)
    			break;
    	}
    
    	close(timerlat_fd);
    	exit(0);
    }
     -------------------------------- >% -----------------------------------
    
    When disabling timerlat, if there is a workload holding the timerlat_fd,
    the SIGKILL will be sent to the thread.
    
    Link: https://lkml.kernel.org/r/69fe66a863d2792ff4c3a149bf9e32e26468bb3a.1686063934.git.bristot@kernel.org
    
    Cc: Juri Lelli <juri.lelli@redhat.com>
    Cc: William White <chwhite@redhat.com>
    Cc: Daniel Bristot de Oliveira <bristot@kernel.org>
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Cc: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: default avatarDaniel Bristot de Oliveira <bristot@kernel.org>
    Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
    e88ed227
trace_output.c 38.9 KB