<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
  <channel>
    <title>Wander Lairson Costa</title>
    <description>Hackers gonna hack</description>
    <link>https://walac.github.io</link>
    <atom:link href="https://walac.github.iofeed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 16 Jan 2026 20:44:34 +0000</pubDate>
    <lastBuildDate>Fri, 16 Jan 2026 20:44:34 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Modernizing stalld with eBPF</title>
        <description>&lt;p&gt;Last year I started working on
&lt;a href=&quot;https://git.kernel.org/pub/scm/utils/stalld/stalld.git/&quot;&gt;stalld&lt;/a&gt;, a daemon
that prevents thread starvation in real-time Linux systems. On systems with
isolated CPUs running high-priority &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; tasks, essential kernel threads can
starve indefinitely. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; monitors CPU run queues and temporarily boosts
starving threads using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SCHED_DEADLINE&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SCHED_FIFO&lt;/code&gt; as fallback).&lt;/p&gt;

&lt;p&gt;The main goal was switching from the old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sched_debug&lt;/code&gt; backend to a new
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_track&lt;/code&gt; backend. The old approach reads &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/sys/kernel/debug/sched/debug&lt;/code&gt;
to get task information — file I/O, parsing, relatively high overhead. The
new approach uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF&lt;/code&gt; programs to track tasks in real-time. Lower overhead,
better precision, but a complete rewrite of the core monitoring logic.&lt;/p&gt;

&lt;p&gt;This post covers what I learned along the way: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eBPF&lt;/code&gt; verifier fights, kernel
portability headaches, race conditions, and production bugs.&lt;/p&gt;

&lt;h2 id=&quot;ebpf-and-the-verifier&quot;&gt;eBPF and the verifier&lt;/h2&gt;

&lt;p&gt;Building the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_track&lt;/code&gt; backend meant diving deep into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eBPF&lt;/code&gt;. The old
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sched_debug&lt;/code&gt; backend had to read and parse text files on every iteration.
With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF&lt;/code&gt;, I track tasks in the kernel as events happen and aggregate the
results before copying to userspace. The overhead reduction is significant,
especially on systems with many CPUs&lt;sup&gt;&lt;a href=&quot;#ft1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eBPF&lt;/code&gt; verifier presents its own challenges. It exists for good reasons —
arbitrary code in the kernel would be a security nightmare. But when it rejects
a program, the error messages can be difficult to diagnose.&lt;/p&gt;

&lt;p&gt;I encountered this with logging. On some kernel versions, the verifier refused
to load the program with “Argument list too long”. The fix was dropping one
parameter from the logging macro:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Original: rejected by verifier on some kernels&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;log_task_prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;enqueue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tgid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Fixed: passes verification&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;log_task_prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;enqueue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tgid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eBPF&lt;/code&gt;, writing correct code is not enough. The code must also convince
the verifier it is correct. And verifier behavior changes between kernel
versions.&lt;/p&gt;

&lt;p&gt;Then there is the kernel itself changing under you. Data structures evolve.
Fields move or disappear entirely. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cpu&lt;/code&gt; field in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct task_struct&lt;/code&gt;
was removed in recent kernels.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href=&quot;https://nakryiko.com/posts/bpf-portability-and-co-re/&quot;&gt;BPF CO-RE&lt;/a&gt;
becomes essential. You define legacy struct variants, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpf_core_field_exists()&lt;/code&gt;
to check at runtime what fields exist, and adapt accordingly:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct___legacy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__always_inline&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;task_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct___legacy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legacy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bpf_core_field_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legacy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BPF_CORE_READ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legacy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BPF_CORE_READ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thread_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I used this pattern again for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__state&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;state&lt;/code&gt; when checking if tasks
are running. Once you’ve written the adaptation logic, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF&lt;/code&gt; loader does
the rest. Different kernels, same binary.&lt;/p&gt;

&lt;h2 id=&quot;tracepoints&quot;&gt;Tracepoints&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_track&lt;/code&gt; backend needed a way to hook into the scheduler and track
task state changes. Early on, I used
&lt;a href=&quot;https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_TRACING/&quot;&gt;fentry&lt;/a&gt;
probes on scheduler functions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enqueue_task_rt()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dequeue_task_rt()&lt;/code&gt;.
This worked in testing, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fentry&lt;/code&gt; requires a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;synchronize_rcu_tasks()&lt;/code&gt; call
during attachment. On a busy system with a high-priority &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; task
monopolizing a CPU, that call can block indefinitely.&lt;/p&gt;

&lt;p&gt;The result was ironic: the daemon designed to prevent starvation was itself
getting starved during startup.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// fentry: requires synchronize_rcu_tasks(), can block&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SEC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fentry/enqueue_task_rt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BPF_PROG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enqueue_task_rt_enter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// tracepoint: no blocking synchronization required&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SEC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tp_btf/sched_wakeup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BPF_PROG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handle__sched_wakeup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Moving to tracepoints resolved the issue. Tracepoints are stable kernel APIs
and do not require blocking synchronization. Startup became immediate, even
on heavily loaded systems.&lt;/p&gt;

&lt;p&gt;However, I then discovered incomplete task tracking. Tasks do more than wake
up and sleep — they migrate between CPUs, get created, and exit. Missing any
of these events causes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; to accumulate stale entries (tasks that no
longer exist on a given CPU) and lose track of tasks that migrated.&lt;/p&gt;

&lt;p&gt;I added handlers for the remaining scheduler events. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sched_wakeup_new&lt;/code&gt; catches
newly created tasks from their first wakeup. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sched_migrate_task&lt;/code&gt; handles CPU
migration — dequeue from the source CPU and re-enqueue on the destination:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SEC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tp_btf/sched_migrate_task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BPF_PROG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handle__sched_migrate_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src_cpu&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dequeue_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enqueue_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The most subtle problem? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; only tracked tasks that changed state after
it started. Anything already on a runqueue was invisible until it rescheduled.
The fix was a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF&lt;/code&gt; task iterator that walks all tasks at startup:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SEC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;iter/task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dump_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bpf_iter__task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task_is_running&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enqueue_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task_cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; has a complete system snapshot from the moment it starts.&lt;/p&gt;

&lt;h2 id=&quot;bug-fixes&quot;&gt;Bug fixes&lt;/h2&gt;

&lt;p&gt;Some bugs manifest clearly. Consider this scenario: a task starts starving,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; detects it and attempts to boost it, but the task exits before the
boost completes. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_current_policy()&lt;/code&gt; syscall fails because the task
no longer exists. However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; was not cleaning up the stale entry,
causing it to retry the same dead PID on every iteration:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[stalld] Failed to get policy for PID 12345
[stalld] Failed to get policy for PID 12345
[stalld] Failed to get policy for PID 12345
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The fix was straightforward once identified. If the syscall fails, the task
has likely exited. Remove the entry and continue:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_current_policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cleanup_starving_task_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boost_with_deadline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cleanup_starving_task_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Other bugs were more subtle. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;merge_taks_info()&lt;/code&gt; function should clear
the starving vector and rebuild it on every iteration. However, it only
cleared the vector when there were zero new tasks. If new tasks existed but
none were starving, the vector retained stale data. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; would then
boost tasks that were no longer starving:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Bug: only clears when no new tasks&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_nr_rt_running&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;update_cpu_starving_vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Fix: unconditionally clear before rebuilding&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;update_cpu_starving_vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A one-line fix, but finding it required understanding the state machine.&lt;/p&gt;

&lt;h2 id=&quot;dl-server-integration&quot;&gt;DL-server integration&lt;/h2&gt;

&lt;p&gt;Recent kernels include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DL-server&lt;/code&gt;, which provides built-in starvation
handling. This raises the question: is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; obsolete?&lt;/p&gt;

&lt;p&gt;The answer is no. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; is now “DL-server aware.” It monitors tasks
system-wide but avoids interfering with tasks that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DL-server&lt;/code&gt; handles.
Instead, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; addresses what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DL-server&lt;/code&gt; cannot: starving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SCHED_FIFO&lt;/code&gt;
tasks, and starving tasks on CPUs where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DL-server&lt;/code&gt; was manually disabled.
The two mechanisms complement each other.&lt;/p&gt;

&lt;p&gt;My initial approach was conservative. If the kernel has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DL-server&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt;
would switch to log-only mode automatically — observe and log, but do not
boost. This avoided potential conflicts and deferred to the built-in solution.
Later, I refined this to the complementary approach described above.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;The migration from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sched_debug&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_track&lt;/code&gt; is complete. Instead of
parsing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debugfs&lt;/code&gt; files, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stalld&lt;/code&gt; now tracks tasks in real-time with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF&lt;/code&gt;.
Lower overhead, better data, and it scales better on systems with lots of CPUs.&lt;/p&gt;

&lt;p&gt;Multiple bugs resolved along the way. Four major &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eBPF&lt;/code&gt; improvements:
tracepoint migration, task iterator, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CO-RE&lt;/code&gt; portability, and verifier
compatibility.&lt;/p&gt;

&lt;h2 id=&quot;going-deeper&quot;&gt;Going deeper&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://git.kernel.org/pub/scm/utils/stalld/stalld.git&quot;&gt;stalld source&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nakryiko.com/posts/bpf-portability-and-co-re/&quot;&gt;BPF CO-RE documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.linuxfoundation.org/realtime/start&quot;&gt;Real-time Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a name=&quot;ft1&quot;&gt;1&lt;/a&gt;: Tested on kernels 5.14 and later. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;queue_track&lt;/code&gt;
backend requires &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BPF CO-RE&lt;/code&gt; support, available in kernels 5.2+ with
appropriate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libbpf&lt;/code&gt; versions.&lt;/p&gt;
</description>
        <pubDate>Fri, 07 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/stalld/</link>
        <guid isPermaLink="true">https://walac.github.io/stalld/</guid>
        
        <category>linux</category>
        
        <category>ebpf</category>
        
        <category>real-time</category>
        
        <category>kernel</category>
        
        <category>debugging</category>
        
        <category>performance</category>
        
        
        <category>kernel</category>
        
      </item>
    
      <item>
        <title>Debugging the Linux Kernel through tracing</title>
        <description>&lt;p&gt;Disclaimer: this is a mental note in the form of a blog
post for future references. Most of it is a summary
of a debug session to solve
&lt;a href=&quot;https://lore.kernel.org/all/171983202713.2215.17043038912457274824.tip-bot2@tip-bot2/&quot;&gt;this issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Kernel is one of hardest piece of software to debug. Although it has some
limited support for a
&lt;a href=&quot;https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-debugging.html&quot;&gt;classical debug session&lt;/a&gt;,
it is often impractical. Not surprisingly, over the years, kernel hackers
developed a lot of tools to aid the art of debugging the Linux kernel.
Tracing tool are among the most useful techniques.&lt;/p&gt;

&lt;p&gt;Tracing is a technique used to monitor the live kernel in real-time, involving 
a logging mechanism to record kernel activity. In this post, we will provide 
an overview of two kernel features that enable tracing: &lt;a href=&quot;https://
docs.kernel.org/trace/tracepoints.html&quot;&gt;tracepoints&lt;/a&gt; and &lt;a href=&quot;https://docs.kernel.org/
trace/kprobes.html&quot;&gt;kprobes&lt;/a&gt;. We’ll interface with these through the &lt;a href=&quot;https://
www.trace-cmd.org/&quot;&gt;trace-cmd&lt;/a&gt; command, though alternatives like &lt;a href=&quot;http://walac.github.io/
kernel-tty/&quot;&gt;bpftrace&lt;/a&gt; can also be used.&lt;/p&gt;

&lt;h2 id=&quot;tracepoints&quot;&gt;Tracepoints&lt;/h2&gt;

&lt;p&gt;A tracepoint is a predefined static hook to call a function (probe) that
allow tracing tools to log system activity. Tracepoints are listed inside
the category &lt;em&gt;events&lt;/em&gt; in the tracing filesystem, under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sys/kernel/tracing/events/&lt;/code&gt;.
You can also list them using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace-cmd list&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd list &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head
&lt;/span&gt;qrtr:qrtr_ns_service_announce_new
qrtr:qrtr_ns_service_announce_del
qrtr:qrtr_ns_server_add
qrtr:qrtr_ns_message
sunrpc:rpc_xdr_sendto
sunrpc:rpc_xdr_recvfrom
sunrpc:rpc_xdr_reply_pages
sunrpc:rpc_clnt_free
sunrpc:rpc_clnt_killall
sunrpc:rpc_clnt_shutdown
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace-cmd&lt;/code&gt; to trace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timer:hrtimer_expire_entry&lt;/code&gt;, which triggers every time
an &lt;a href=&quot;https://docs.kernel.org/timers/hrtimers.html&quot;&gt;hrtimer&lt;/a&gt; callback executes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;trace-cmd record -e timer:hrtimer_expire_entry sleep 0.01
CPU0 data recorded at offset=0x2a5000
    197 bytes in size (4096 uncompressed)
CPU1 data recorded at offset=0x2a6000
    212 bytes in size (4096 uncompressed)
CPU2 data recorded at offset=0x2a7000
    132 bytes in size (4096 uncompressed)
CPU3 data recorded at offset=0x2a8000
    163 bytes in size (4096 uncompressed)
CPU4 data recorded at offset=0x2a9000
    211 bytes in size (4096 uncompressed)
CPU5 data recorded at offset=0x2aa000
    209 bytes in size (4096 uncompressed)
CPU6 data recorded at offset=0x2ab000
    189 bytes in size (4096 uncompressed)
CPU7 data recorded at offset=0x2ac000
    189 bytes in size (4096 uncompressed)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace-cmd record&lt;/code&gt; captures events while the given command runs. In this
example, we ran sleep 0.01 to capture events for just 10ms, as hrtimer
generates many entries.&lt;/p&gt;

&lt;p&gt;The logs are saved in a binary file named &lt;em&gt;trace.dat&lt;/em&gt;. To convert these logs
to a text format, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace-cmd report&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;trace-cmd report | &lt;span class=&quot;nb&quot;&gt;head 
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;002] 21403.059823: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffe3163cf8 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402099965347 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;007] 21403.059855: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffe0fcfb20 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402099998095 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
           Timer-34807 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;002] 21403.059858: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc326158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100001643 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
 IPDL Background-4695  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;003] 21403.059859: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc3a6158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100001860 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
           sleep-45035 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21403.059859: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc2a6158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100001874 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
 Isolated Web Co-29032 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;004] 21403.059859: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc426158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100002003 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;006] 21403.059861: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc526158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100004124 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;005] 21403.059863: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc4a6158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100006647 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
    dav1d-worker-44563 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;000] 21403.059864: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90d2cc226158 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21402100006686 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tick_nohz_handler/0x0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The logs are dominated by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tick_nohz_handler&lt;/code&gt; function,
but we can filter it out using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-f&lt;/code&gt; option:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; tick_nohz_handler /proc/kallsyms | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos; &apos;&lt;/span&gt;
ffffffff86232650
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; timer:hrtimer_expire_entry &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;function != 0xffffffff86232650&apos;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;0.01
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function parameter is a machine-sized integer containing the address of the
callback function. We must translate the function name to its address
using the &lt;em&gt;/proc/kallsyms&lt;/em&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd report
&lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;006] 21953.174222: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffc6b43d10 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952218640837 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21953.174606: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffc1e17c18 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952219021472 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
        Renderer-4729  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21953.175599: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90cf80307c98 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952220003877 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;intel_uncore_fw_release_timer/0x0
        Renderer-4729  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21953.175602: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90cf8191d418 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952220003877 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;intel_uncore_fw_release_timer/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;007] 21953.177506: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffe3163a58 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952221925981 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
        Renderer-4729  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21953.179598: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff90cf80307c98 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952224002950 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;intel_uncore_fw_release_timer/0x0
    dav1d-worker-45360 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;002] 21953.182593: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffe0fcfb88 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952227002482 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;001] 21953.183062: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffcd667c58 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952227481587 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
    dav1d-worker-45358 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;007] 21953.184810: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffe062fc10 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952229231336 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
           sleep-45667 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;000] 21953.184852: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffc2ae7b10 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952229272526 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
           sleep-45667 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;000] 21953.184944: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffc143f810 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;21952229364853 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To view the fields available for filtering and their types, print the event
format:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd list &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; timer:hrtimer_expire_entry &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;
system: timer
name: hrtimer_expire_entry
ID: 388
format:
        field:unsigned short common_type&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       offset:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       size:2&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        field:unsigned char common_flags&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       offset:2&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       size:1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        field:unsigned char common_preempt_count&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       offset:3&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       size:1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        field:int common_pid&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   offset:4&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       size:4&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        field:void &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; hrtimer&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   offset:8&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       size:8&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        field:s64 now&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  offset:16&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      size:8&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        field:void &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  offset:24&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      size:8&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; signed:0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The fields prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;common_&lt;/code&gt; are common to all events from the same system.
Say, you want to trace all timer events but only for a specific PID:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;timer:*&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;common_pid == 1&apos;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To get the stack trace for each event, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-T&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; timer:hrtimer_expire_entry &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;function != 0xffffffff86232650&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;0.01
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd report
&lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;002] 24703.375192: hrtimer_expire_entry: &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffacffc616fdc0 &lt;span class=&quot;nv&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;24702442127437 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;hrtimer_wakeup/0x0
          &amp;lt;idle&amp;gt;-0     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;002] 24703.375200: kernel_stack:         &amp;lt;stack trace &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; trace_event_raw_event_hrtimer_expire_entry &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff86218921&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; __hrtimer_run_queues &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8621c491&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; hrtimer_interrupt &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8621d1aa&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; __sysvec_apic_timer_interrupt &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8608db25&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; sysvec_apic_timer_interrupt &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8715a20c&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; asm_sysvec_apic_timer_interrupt &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8720160a&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; cpuidle_enter_state &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8715c2f9&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; cpuidle_enter &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff86de023d&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; do_idle &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8619ef17&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; cpu_startup_entry &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8619f179&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; start_secondary &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8608bacb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; common_startup_64 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff8603ddad&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Static probes are invaluable for understanding system behavior, but they
require kernel developers to make them available. What if you need to trace
a part of the kernel without tracepoints?&lt;/p&gt;

&lt;h2 id=&quot;kernel-probes&quot;&gt;Kernel probes&lt;/h2&gt;

&lt;p&gt;Kernel probes, also known as kprobes, allow you to dynamically create
tracepoints to log information. These probes can be attached to almost any
kernel address, including functions and their entry/exit points.&lt;/p&gt;

&lt;p&gt;To create a probe, you can write directly to the tracing filesystem, but
I rather prefer to use
&lt;a href=&quot;https://man7.org/linux/man-pages/man1/perf-probe.1.html&quot;&gt;perf-probe&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#ft1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;A few weeks ago I was debugging a
&lt;a href=&quot;https://lore.kernel.org/all/171983202713.2215.17043038912457274824.tip-bot2@tip-bot2/&quot;&gt;memory leak&lt;/a&gt;
reported in the RT kernel. At some point I realized there was something odd between the
&lt;a href=&quot;https://docs.kernel.org/scheduler/sched-deadline.html&quot;&gt;deadline scheduler&lt;/a&gt; and the
hrtimer (now you know why I previously picked the hrtimer as a tracepoint example).
The entry point to start the timer is the function
&lt;a href=&quot;https://elixir.bootlin.com/linux/v6.10-rc6/source/kernel/sched/deadline.c#L1044&quot;&gt;start_dl_timer&lt;/a&gt;.
Unfortunately, there is no tracepoint we can use to track its call. Let’s create
one:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;perf probe start_dl_timer
Added new event:
  probe:start_dl_timer &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;on start_dl_timer&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; probe:start_dl_timer &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice that, by default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perf-probe&lt;/code&gt; put the probe inside the “probe” group.
This is all good but doesn’t give much information. We would like to know the PID,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_struct&lt;/code&gt; reference count and the timer object to relate to the hrtimer tracepoints.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start_dl_timer&lt;/code&gt; receives a pointer to
&lt;a href=&quot;https://elixir.bootlin.com/linux/v6.10-rc6/source/include/linux/sched.h#L598&quot;&gt;struct sched_dl_entity&lt;/a&gt;,
containing the
&lt;a href=&quot;https://elixir.bootlin.com/linux/v6.10-rc6/source/include/linux/sched.h#L651&quot;&gt;timer object&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perf-probe&lt;/code&gt;
allows you to dereference struct members, so adding the timer object to the trace is a piece of cake.
Firstly, we need to remove the previously defined probe:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;perf probe &lt;span class=&quot;nt&quot;&gt;--del&lt;/span&gt; probe:start_dl_timer
Removed event: probe:start_dl_timer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see which lines we can probe:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;perf probe &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; start_dl_timer
      0  static int start_dl_timer&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;struct sched_dl_entity &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;dl_se&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      2         struct hrtimer &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;timer &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;amp;dl_se-&amp;gt;dl_timer&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                struct dl_rq &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;dl_rq &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; dl_rq_of_se&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dl_se&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                struct rq &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;rq &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; rq_of_dl_rq&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dl_rq&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                ktime_t now, act&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                s64 delta&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
         
                lockdep_assert_rq_held&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;rq&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
         
                /&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; We want the timer to fire at the deadline, but considering
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; that it is actually coming from rq-&amp;gt;clock and not from
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; hrtimer&lt;span class=&quot;s1&quot;&gt;&apos;s time base reading.
                 */
                act = ns_to_ktime(dl_next_period(dl_se));
     16         now = hrtimer_cb_get_time(timer);
     17         delta = ktime_to_ns(now) - rq_clock(rq);
                act = ktime_add_ns(act, delta);
         
                /*
                 * If the expiry time already passed, e.g., because the value
                 * chosen as the deadline is too small, don&apos;&lt;/span&gt;t even try to
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; start the timer &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the past!
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/
     25         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ktime_us_delta&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;act, now&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &amp;lt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
         
                /&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;enqueued will guarantee another callback&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; even &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;one is already &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; progress. This ensures a balanced &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;get,put&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;_task_struct&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; The race against __run_timer&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; clearing the enqueued state is
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; harmless because we&lt;span class=&quot;s1&quot;&gt;&apos;re holding task_rq()-&amp;gt;lock, therefore the timer
                 * expiring after we&apos;&lt;/span&gt;ve &lt;span class=&quot;k&quot;&gt;done &lt;/span&gt;the check will &lt;span class=&quot;nb&quot;&gt;wait &lt;/span&gt;on its task_rq_lock&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; and observe our state.
                 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/
     37         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;hrtimer_is_queued&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
     38                 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;dl_server&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dl_se&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
     39                         get_task_struct&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dl_task_of&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dl_se&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
     40                 hrtimer_start&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;timer, act, HRTIMER_MODE_ABS_HARD&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
         
                &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-L&lt;/code&gt; option lists the source code line numbers where we can install
the probe hook&lt;sup&gt;&lt;a href=&quot;#ft2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Line 16 seems a good candidate, since the line 2 defines a local timer
variable that holds the timer address. This is useful because we don’t
have a syntax in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perf-probe&lt;/code&gt; to take the address of a struct member.
Just to illustrate member dereference, we will also print the timer
function. Let’s confirm which variables are available to use:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;perf probe &lt;span class=&quot;nt&quot;&gt;-V&lt;/span&gt; start_dl_timer:16
Available variables at start_dl_timer:16
        @&amp;lt;start_dl_timer+67&amp;gt;
                ktime_t act
                struct dl_rq&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;   dl_rq
                struct hrtimer&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; timer
                struct rq&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;      rq
                struct sched_dl_entity&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; dl_se
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The syntax to specify a function and line number is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;function&amp;gt;:&amp;lt;line&amp;gt;&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-V&lt;/code&gt; option shows the available variables.&lt;/p&gt;

&lt;p&gt;We mentioned we want to print the PID and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_struct&lt;/code&gt; reference count.
But where are they? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl_se&lt;/code&gt; is a member of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_struct&lt;/code&gt; (called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl&lt;/code&gt; inside
the struct), so we can get the pointer to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_struct&lt;/code&gt; using the
&lt;a href=&quot;https://elixir.bootlin.com/linux/v6.10-rc6/source/include/linux/container_of.h#L18&quot;&gt;container_of&lt;/a&gt;
macro. There is only one problem: we don’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;container_of&lt;/code&gt;! But we can do it manually
if we know the offset of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl_se&lt;/code&gt;
&lt;a href=&quot;https://elixir.bootlin.com/linux/v6.10-rc6/source/include/linux/sched.h#L803&quot;&gt;inside task_struct&lt;/a&gt;.
We can do it with the help of &lt;a href=&quot;https://www.sourceware.org/gdb/&quot;&gt;gdb&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; gdb /usr/lib/debug/lib/modules/&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;/vmlinux
Reading symbols from /usr/lib/debug/lib/modules/5.14.0-469.el9.x86_64/vmlinux...
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; p &amp;amp;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;struct task_struct &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;-&amp;gt;dl
&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;struct sched_dl_entity &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 0x280
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; p &amp;amp;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;struct task_struct &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;-&amp;gt;pid
&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pid_t &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 0xa98
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; p &amp;amp;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;struct task_struct &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;-&amp;gt;usage
&lt;span class=&quot;nv&quot;&gt;$3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;refcount_t &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 0x30
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This little trick works by casting 0 to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct task_struct *&lt;/code&gt; and then
taking the address of the of field we are interested. This will give the
field offset. Now we know the layout of the struct:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;refcount_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// offset 0x30&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sched_dl_entity&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// offset 0x280&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pid_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;// offset 0xa98&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the function argument, we know the address of the field &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task_struct&lt;/code&gt; address is obtained by subtracting 0x280 from
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl_se&lt;/code&gt; pointer parameter. From there, to get a field address,
just add the respective offset:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;usage   = -0x280 + 0x030 = -0x250
pid     = -0x280 + 0xa98 = +0x818
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can finally define our custom probe:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;perf probe &lt;span class=&quot;s1&quot;&gt;&apos;start_dl_timer:16 hrtimer=timer timer-&amp;gt;function pid=+0x818(%di) usage=-0x250(%di)&apos;&lt;/span&gt;
Added new event:
  probe:start_dl_timer_L16 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;on start_dl_timer:16 with &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;timer &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;timer-&amp;gt;function &lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;+0x818&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%di&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;usage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-0x250&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;%di&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice we can give a name to the probe parameters, and also we can dereference
structures to get their members. The field name becomes the probe parameter
name if we don’t give one explicitly. Also notice the usage of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rdi&lt;/code&gt; register
here&lt;sup&gt;&lt;a href=&quot;#ft3&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. According to the
&lt;a href=&quot;https://wiki.osdev.org/System_V_ABI#x86-64&quot;&gt;x86_64 calling convention&lt;/a&gt;,
it holds the function first argument. In our case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dl_se&lt;/code&gt;. Also, we had
to specify the type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s32&lt;/code&gt; for pid and usage parameters. If you don’t specify
a type, the default type is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x64&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s32&lt;/code&gt; means &lt;em&gt;signed 32 bits&lt;/em&gt;. Let’s use
our new custom probe:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; probe:start_dl_timer_L16 stress-ng &lt;span class=&quot;nt&quot;&gt;--cyclic&lt;/span&gt; 5 &lt;span class=&quot;nt&quot;&gt;--timeout&lt;/span&gt; 10s &lt;span class=&quot;nt&quot;&gt;--minimize&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--quiet&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd report
&lt;span class=&quot;nv&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
 stress-ng-cycli-51628 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;000] 79677.069484: start_dl_timer_L16:   &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff84b6c843&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff9f9dcaa649d8 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffffff84b72150 &lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;51628 &lt;span class=&quot;nv&quot;&gt;usage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
 stress-ng-cycli-51628 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;000] 79677.069708: start_dl_timer_L16:   &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ffffffff84b6c843&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hrtimer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffff9f9dcaa649d8 &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xffffffff84b72150 &lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;51628 &lt;span class=&quot;nv&quot;&gt;usage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can again consult the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/kallsyms&lt;/code&gt; to check what function is the hrtimer callback:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;ffffffff84b72150 /proc/kallsyms 
ffffffff84b72150 t dl_task_timer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this post, we explored the fundamentals of tracing the Linux kernel using
static tracepoints and dynamic probes. These tools offer a powerful and
flexible means of diagnosing and understanding kernel behavior. If you have
any questions or comments, feel free to leave them below.&lt;/p&gt;

&lt;h2 id=&quot;going-deeper&quot;&gt;Going deeper&lt;/h2&gt;

&lt;p&gt;This post only scratches the surface. If you’re eager to delve deeper,
here are some valuable resources:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kernel.org/doc/html/v4.19/trace/events.html&quot;&gt;Event Tracing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kernel.org/doc/html/v4.19/trace/kprobetrace.html&quot;&gt;Kprobe-base Event Tracing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/perf-probe.1.html&quot;&gt;perf-probe man page&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.trace-cmd.org/&quot;&gt;trace-cmd website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a name=&quot;ft1&quot;&gt;1&lt;/a&gt;: perf probes are not exactly the same as kernel probes,
but in practice the differences don’t matter.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft2&quot;&gt;1&lt;/a&gt;: you need the kernel debug symbols installed. For
RHEL base systems, install it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnf install -y kernel-debuginfo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft3&quot;&gt;2&lt;/a&gt;: the probe syntax does not make a difference between
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rdi&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edi&lt;/code&gt;. You just specify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;di&lt;/code&gt;. The same thing applies to the
other registers.&lt;/p&gt;
</description>
        <pubDate>Mon, 24 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/kernel-tracing/</link>
        <guid isPermaLink="true">https://walac.github.io/kernel-tracing/</guid>
        
        <category>kernel</category>
        
        <category>trace</category>
        
        
        <category>kernel</category>
        
      </item>
    
      <item>
        <title>Improving the Kernel TTY throughput</title>
        <description>&lt;p&gt;It is incredible how we can find room for improvement even in the eldest
and battle-tested codebases out there. This post is about one of these
cases.&lt;/p&gt;

&lt;p&gt;I was investigating a &lt;a href=&quot;https://is.gd/AasYhu&quot;&gt;soft lockup&lt;/a&gt; bug report which
only happened in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HP Proliant DL380 Gen9&lt;/code&gt;. The trigger for the issue is
when we try to load the &lt;a href=&quot;https://is.gd/pBmMXP&quot;&gt;scsi_debug&lt;/a&gt; with a few hundred
virtual devices:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;modprobe scsi_debug &lt;span class=&quot;nv&quot;&gt;virtual_gb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;nv&quot;&gt;add_host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2 &lt;span class=&quot;nv&quot;&gt;num_tgts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;600
Message from syslogd@storageqe-25 at Jul 15 10:29:35 ...
 kernel:watchdog: BUG: soft lockup - CPU#33 stuck &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;22s! &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;modprobe:35056]

Message from syslogd@storageqe-25 at Jul 15 10:30:23 ...
 kernel:watchdog: BUG: soft lockup - CPU#25 stuck &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;22s! &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;migration/25:140]

Message from syslogd@storageqe-25 at Jul 15 10:30:23 ...
 kernel:watchdog: BUG: soft lockup - CPU#18 stuck &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;23s! &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;modprobe:35056]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And below, we show the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; output:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;watchdog: BUG: soft lockup - CPU#33 stuck &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;22s! &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;modprobe:35056]
rcu: 	14-...!: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1 GPs behind&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;24a/1/0x4000000000000002 &lt;span class=&quot;nv&quot;&gt;softirq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;12191/12192 &lt;span class=&quot;nv&quot;&gt;fqs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5030
Modules linked &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;:
rcu: 	33-...!: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;20094 ticks this GP&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;idle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;f9e/1/0x4000000000000000 &lt;span class=&quot;nv&quot;&gt;softirq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8891/8891 &lt;span class=&quot;nv&quot;&gt;fqs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5031
 scsi_debug
	&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;detected by 14, &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;80246 jiffies, &lt;span class=&quot;nv&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;346621, &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;270790&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
 loop
NMI backtrace &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;cpu 14
 dm_service_time
CPU: 14 PID: 0 Comm: swapper/14 Tainted: G               X &lt;span class=&quot;nt&quot;&gt;---------&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
 dm_multipath
Hardware name: HP ProLiant DL380 Gen9/ProLiant DL380 Gen9, BIOS P89 02/17/2017
 rfkill
Call Trace:
 intel_rapl_msr
 &amp;lt;IRQ&amp;gt;
 intel_rapl_common sb_edac
 dump_stack+0x64/0x7c
...
...
CPU: 18 PID: 35056 Comm: modprobe Tainted: G             L X &lt;span class=&quot;nt&quot;&gt;---------&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
Hardware name: HP ProLiant DL380 Gen9/ProLiant DL380 Gen9, BIOS P89 02/17/2017
RIP: 0010:number+0x21b/0x340
Code: 4c 8d 44 28 01 48 39 c3 76 03 c6 00 20 48 ...
RSP: 0018:ffffb03ec3650b98 EFLAGS: 00000046
RAX: 0000000000000000 RBX: ffffb03f43650cff RCX: 0000000000000038
RDX: ffffb03ec3650baf RSI: 0000000000000001 RDI: 0000000000000000
RBP: 00000000fffffffd R08: ffffb03ec3650d06 R09: 0000000000000004
R10: ffffb03ec3650c98 R11: ffffb03ec3650d06 R12: 0000000000000020
R13: 0000000000000000 R14: 0000000000004a0e R15: 0000000000000a00
FS:  00007f519cfb1740&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0000&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; GS:ffff9b096fa00000&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0000&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055a8b65190b8 CR3: 0000000550bec004 CR4: 00000000001706e0
Call Trace:
 &amp;lt;IRQ&amp;gt;
 vsnprintf+0x363/0x560
 sprintf+0x56/0x70
 info_print_prefix+0x7b/0xd0
 record_print_text+0x52/0x150
 console_unlock+0x144/0x330
 vprintk_emit+0x14d/0x230
 printk+0x58/0x6f
 print_modules+0x62/0xaf
 watchdog_timer_fn+0x190/0x200
 ? lockup_detector_update_enable+0x50/0x50
 __hrtimer_run_queues+0x12a/0x270
 hrtimer_interrupt+0x110/0x2c0
 __sysvec_apic_timer_interrupt+0x5f/0xd0
 sysvec_apic_timer_interrupt+0x6d/0x90
 &amp;lt;/IRQ&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printk()&lt;/code&gt; and (in special) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console_unlock()&lt;/code&gt; in the stack trace.
This is not a coincidence. It happened every single time.&lt;/p&gt;

&lt;p&gt;I found out that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scsi_debug&lt;/code&gt; sends a lot of information to the console output,
causing the kernel to spend most of its time flushing data to the serial TTY.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vprintk_emit()&lt;/code&gt; disables preemption before calling
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console_unlock()&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#ft1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Because the preemption is disabled
and the serial TTY driver holds a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spinlock&lt;/code&gt; while writing to the port, the
&lt;a href=&quot;https://docs.kernel.org/RCU/stallwarn.html&quot;&gt;RCU stall detector&lt;/a&gt; reports a stall.
A slow serial console causing an RCU stall is well known and
&lt;a href=&quot;https://docs.kernel.org/RCU/stallwarn.html&quot;&gt;documented&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Booting Linux using a console connection that is too slow to keep up with the boot-time
console-message rate. For example, a 115Kbaud serial console can be way too slow to keep
up with boot-time message rates and will frequently result in RCU CPU stall warning
messages. Especially if you have added debug printk()s.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hrtimer&lt;/code&gt; interrupt handler, the kernel calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;check_rcu_stall()&lt;/code&gt; function,
which will call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printk()&lt;/code&gt; to dump the stall information. At this time, the interrupt handler
becomes the console owner and keeps flushing the remaining data to the serial
console&lt;sup&gt;&lt;a href=&quot;#ft2&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. The CPU will then get stuck in the interrupt routine, and
triggers a soft lockup.&lt;/p&gt;

&lt;p&gt;I suspected there was something odd with the serial port. It is configured with
115200 bps, 8 bits per data. Considering one start bit and one stop bit, it gives
an expected throughput of approximately 11520 bytes per second. Let’s use
&lt;a href=&quot;https://github.com/iovisor/bpftrace&quot;&gt;bpftrace&lt;/a&gt; while loading the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scsi_debug&lt;/code&gt;
driver to verify if it is indeed the case:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bpftrace &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;
BEGIN {
	@ = 0;
}

kfunc:serial8250_console_putchar {
	@++;
}

interval:s:1 {
	printf(&quot;%d B/s\n&quot;, @);
	@ = 0;
}&apos;&lt;/span&gt;
Attaching 3 probes...
2522 B/s
2517 B/s
2518 B/s
2507 B/s
2510 B/s
2414 B/s
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;serial8250_console_putchar()&lt;/code&gt; is the function that effectively writes
a character to the serial port. We count how many times we call it per
second.&lt;/p&gt;

&lt;p&gt;Maybe the tracing machinery is causing an overhead, jeopardizing
the serial performance? Let’s try another approach:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bpftrace &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;
BEGIN {
	@ = (uint32) 0;
}

kfunc:uart_console_write {
	@ += args-&amp;gt;count;
}

interval:s:1 {
	printf(&quot;%u B/s\n&quot;, @);
	@ = 0;
}&apos;&lt;/span&gt;
Attaching 3 probes...
1838 B/s
2460 B/s
2536 B/s
2415 B/s
2461 B/s
2247 B/s
2521 B/s
2441 B/s
2409 B/s
2378 B/s
2353 B/s
2398 B/s
2376 B/s
2414 B/s
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which has less overhead, as we don’t call the probe function for each
character sent. Again the throughput is not what we would expect.&lt;/p&gt;

&lt;p&gt;The scripts above report the overall system throughput. The next step
is determining if the suboptimal performance is due to system overhead
or the serial TTY code itself. The following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bpftrace&lt;/code&gt; script measures
more precisely the throughput of the serial console driver:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bpftrace &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;
kfunc:uart_console_write {
  @c[cpu] = args-&amp;gt;count;
  @t[cpu] = nsecs;
}

kretfunc:uart_console_write {
  $elapsed = nsecs - @t[cpu];
  $rate = @c[cpu] * 1000000000 / $elapsed;
  printf(&quot;%ld B/s\n&quot;, $rate);
}&apos;&lt;/span&gt;
Attaching 2 probes...
2206 B/s
2502 B/s
2585 B/s
2553 B/s
2559 B/s
2537 B/s
2555 B/s
2557 B/s
2554 B/s
2557 B/s
2561 B/s
2542 B/s
2534 B/s
2255 B/s
2555 B/s
2482 B/s
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No luck. To facilitate my tests, I created a
&lt;a href=&quot;https://github.com/walac/serial-console-test&quot;&gt;small driver + app&lt;/a&gt;
that calls the console driver the same way &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printk()&lt;/code&gt; does. After
loading the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;serco&lt;/code&gt; driver, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sertest -n &amp;lt;N&amp;gt; &amp;lt;driver-path&amp;gt;&lt;/code&gt; to
send &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; bytes to the console. Let’s test it:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./sertest &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 2500 /dev/serco

real    0m0.997s
user    0m0.000s
sys     0m0.997s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, 2500 bytes sent in approximately 1 second. That matches our previous
results. With the help of the &lt;a href=&quot;https://trace-cmd.org/&quot;&gt;function tracer&lt;/a&gt;,
we can see what is going on in more detail:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd record &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; function_graph &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; serial8250_console_write &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   ./sertest &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1 /dev/serco

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;trace-cmd report

            |  serial8250_console_write&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 0.384 us   |    _raw_spin_lock_irqsave&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 1.836 us   |    io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 1.667 us   |    io_serial_out&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            |    uart_console_write&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            |      serial8250_console_putchar&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            |        wait_for_xmitr&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 1.870 us   |          io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 2.238 us   |        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 1.737 us   |        io_serial_out&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 4.318 us   |      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 4.675 us   |    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            |    wait_for_xmitr&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 1.635 us   |      io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            |      __const_udelay&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 1.125 us   |        delay_tsc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 1.429 us   |      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
...
...
...
 1.683 us   |      io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            |      __const_udelay&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 1.248 us   |        delay_tsc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 1.486 us   |      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 1.671 us   |      io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 411.342 us |    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, it takes 411 us to send just one single byte.
The function &lt;a href=&quot;https://is.gd/EfkkTZ&quot;&gt;serial8250_console_write()&lt;/a&gt;
is the one responsible to dispatch the TTY data to the serial port (it
calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uart_console_write()&lt;/code&gt;). It writes a character and waits for the
chip controller to process the data before sending the next. Modern
serial controllers have a FIFO of at least 16 bytes. Maybe we can
exploit that and improve the situation. Well, that is what
&lt;a href=&quot;https://is.gd/pk2Yje&quot;&gt;I did&lt;/a&gt;. Let’s how things go now:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./sertest &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 2500 /dev/serco

real    0m0.112s
user    0m0.056s
sys     0m0.055s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wow! Much better! Now, if we send 11500 bytes, it should take approximately one second:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./sertest &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 11500 /dev/serco

real    0m3.142s
user    0m0.000s
sys     0m3.142s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/confused.jpg&quot; alt=&quot;confused&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace-cmd&lt;/code&gt; one more time, but I will only show the piece of
the trace output that interests us:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845784: funcgraph_exit:         1.942 us   |        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845784: funcgraph_entry:        1.710 us   |        io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845786: funcgraph_entry:                   |        __const_udelay&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845786: funcgraph_entry:                   |          delay_tsc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845786: funcgraph_entry:        0.128 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845787: funcgraph_entry:        0.130 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845787: funcgraph_entry:        0.130 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845787: funcgraph_entry:        0.131 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845787: funcgraph_entry:        0.131 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845788: funcgraph_entry:        0.130 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845788: funcgraph_exit:         1.666 us   |          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845788: funcgraph_exit:         1.915 us   |        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845788: funcgraph_entry:      + 12.787 us  |        io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845801: funcgraph_entry:                   |        __const_udelay&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845801: funcgraph_entry:                   |          delay_tsc&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845801: funcgraph_entry:        0.152 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845802: funcgraph_entry:        0.151 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845802: funcgraph_entry:        0.151 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845802: funcgraph_entry:        0.143 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845803: funcgraph_entry:        0.145 us   |            preempt_count_add&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845803: funcgraph_entry:        0.147 us   |            preempt_count_sub&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845803: funcgraph_exit:         1.909 us   |          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845803: funcgraph_exit:         2.204 us   |        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845803: funcgraph_entry:        1.743 us   |        io_serial_in&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
sertest-21649 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;008]  2360.845805: funcgraph_entry:                   |        __const_udelay&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;io_serial_in()&lt;/code&gt; usually executes in less than 2 us, but
sometimes something odd happens, and the controller takes more than 10
us to reply. That is the reason we can’t get the expected speed of 115200 bps
for such an amount of data.&lt;/p&gt;

&lt;p&gt;We see a 25% throughput boost when working with the original
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modprobe sci_debug&lt;/code&gt; scenario. Even though we could not reach
maximum performance, we improved things considerably.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft1&quot;&gt;1&lt;/a&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console_unlock()&lt;/code&gt; will flush the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printk()&lt;/code&gt; ring
buffer before unlocking the console.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft2&quot;&gt;1&lt;/a&gt;: This behavior is vital to ensure essential
information flushes from the ring buffer in the case of fatal errors.&lt;/p&gt;
</description>
        <pubDate>Wed, 31 Aug 2022 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/kernel-tty/</link>
        <guid isPermaLink="true">https://walac.github.io/kernel-tty/</guid>
        
        <category>linux</category>
        
        <category>kernel</category>
        
        <category>tty</category>
        
        
        <category>kernel</category>
        
      </item>
    
      <item>
        <title>A crash course on debugging kernel crashes using the crash utility</title>
        <description>&lt;p&gt;The other day I was working on a bug where
&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/8/html-single/installation_guide/index&quot;&gt;kernel-rt-debug&lt;/a&gt;
reported some warnings in the middle of the
&lt;a href=&quot;https://www.kernel.org/doc/html/latest/RCU/torture.html&quot;&gt;rcutorture&lt;/a&gt; test
followed by a kernel hang:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rcu_torture_writer: Testing asynchronous GPs. 
rcu_torture_writer: Testing normal GPs. 
------------[ cut here ]------------ 
DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt)) 
WARNING: CPU: 2 PID: 7996 at kernel/softirq.c:169 __local_bh_disable_ip+0x4ae/0x800 
Modules linked in: rcutorture torture rpcsec_gss_krb5 auth_rpcgss nfsv4 ....
CPU: 2 PID: 7996 Comm: rcu_torture_rea Kdump: loaded Not tainted 4.18.0-240.10.rt14.5.el8.x86_64+debug #1 
Hardware name: Hewlett-Packard ProLiant DL388eGen8, BIOS P73 06/01/2012 
RIP: 0010:__local_bh_disable_ip+0x4ae/0x800 
Code: 08 84 d2 0f 85 c7 02 00 00 8b 15 bd f7 73 07 85 d2 0f 85 37 fc ff ff 48 c7 c6 80 fd e7 8e 48 c7 ...
RSP: 0018:ffff8883d243fab0 EFLAGS: 00010286 
RAX: 0000000000000000 RBX: 0000000000000200 RCX: 0000000000000000 
RDX: 0000000000000004 RSI: 0000000000000004 RDI: 0000000000000246 
RBP: ffff8883d243fae8 R08: fffffbfff1f08f59 R09: fffffbfff1f08f58 
R10: 0000000000000000 R11: ffffffff8f847ac3 R12: ffff888104d88000 
R13: 0000000000000010 R14: ffff8883d243fb98 R15: 0000000000000064 
FS:  0000000000000000(0000) GS:ffff8883d3800000(0000) knlGS:0000000000000000 
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 
CR2: 000056094f904f44 CR3: 00000002c8228005 CR4: 00000000000606e0 
Call Trace: 
 ? rcutorture_one_extend+0x5af/0xa30 [rcutorture] 
 rcutorture_one_extend+0x5c0/0xa30 [rcutorture] 
 rcu_torture_one_read+0x562/0x900 [rcutorture] 
 ? rcutorture_one_extend+0xa30/0xa30 [rcutorture] 
 ? lock_timer_base+0x112/0x260 
 ? lock_downgrade+0x6f0/0x6f0 
 rcu_torture_reader+0x240/0x53d [rcutorture] 
 ? rcu_torture_timer+0x1c0/0x1c0 [rcutorture] 
 ? lock_downgrade+0x6f0/0x6f0 
 ? lock_contended+0xde0/0xde0 
 ? lock_acquire+0x134/0x4b0 
 ? rcu_torture_one_read+0x900/0x900 [rcutorture] 
 ? trace_hardirqs_on_caller+0x309/0x4d0 
 ? _raw_spin_unlock_irqrestore+0x45/0xf0 
 ? __kthread_parkme+0xb6/0x180 
 ? rcu_torture_timer+0x1c0/0x1c0 [rcutorture] 
 kthread+0x30c/0x3d0 
 ? kthread_create_on_node+0xc0/0xc0 
 ret_from_fork+0x3a/0x50 
irq event stamp: 10175619 
hardirqs last  enabled at (10175619): [&amp;lt;ffffffff8e8c8c74&amp;gt;] _raw_spin_unlock_irq+0x24/0xd0 
hardirqs last disabled at (10175618): [&amp;lt;ffffffff8e8baabc&amp;gt;] __schedule+0x1bc/0x22f0 
softirqs last  enabled at (10175616): [&amp;lt;ffffffff8cbefc15&amp;gt;] __local_bh_enable_ip+0xb5/0x1a0 
softirqs last disabled at (10175613): [&amp;lt;ffffffffc18d6aef&amp;gt;] rcutorture_one_extend+0x5af/0xa30 [rcutorture] 
---[ end trace 0000000000000002 ]--- 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The log is bigger than that but for this post only this part is worthy.
The warning reported is from
&lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/tree/kernel/softirq.c?h=linux-5.12.y-rt-rebase#n173&quot;&gt;this code fragment&lt;/a&gt;
&lt;sup&gt;&lt;a href=&quot;#ft1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__local_bh_disable_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;WARN_ON_ONCE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_hardirq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;cm&quot;&gt;/* First entry of a task into a BH disabled section? */&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;softirq_disable_cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preemptible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;local_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;softirq_ctrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;cm&quot;&gt;/* Required to meet the RCU bottomhalf requirements. */&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rcu_read_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;DEBUG_LOCKS_WARN_ON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this_cpu_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;softirq_ctrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As shown in the log above, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt; is called by
&lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/tree/kernel/rcu/rcutorture.c?h=linux-5.12.y-rt-rebase#n1410&quot;&gt;rcutorture_one_extend&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rcutorture_one_extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torture_random_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rt_read_seg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rtrsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idxnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statesold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;WARN_ON_ONCE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;WARN_ON_ONCE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_SHIFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rtrsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt_readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;cm&quot;&gt;/*
   * First, put new protection in place to avoid critical-section gap.
   * Disable preemption around the ATOM disables to ensure that
   * in_atomic() is true.
   */&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_BH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;local_bh_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_RBH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rcu_read_lock_bh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_IRQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;local_irq_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_PREEMPT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;preempt_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_SCHED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rcu_read_lock_sched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;preempt_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_ATOM_BH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;local_bh_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_ATOM_RBH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rcu_read_lock_bh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;preempt_enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As shown, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt; in more than
one location. As the functions offsets also appear in the log, finding
the source code line is straightforward. I will show you how to do it later.
What I am really interested in is the values of the variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt;, as they control several conditional calls this function makes.
Knowing the value of these variables will help us
have a better idea about the context in which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt; was called
when it triggered the warning.&lt;/p&gt;

&lt;p&gt;In the rest of this post, I am going to use the
&lt;a href=&quot;https://github.com/crash-utility/crash&quot;&gt;crash utility&lt;/a&gt; to reveal the value of
these variables. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Crash&lt;/code&gt; is an extension of
&lt;a href=&quot;https://www.gnu.org/software/gdb/&quot;&gt;gdb&lt;/a&gt; so we can utilize it to debug kernel and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Kdump_(Linux)&quot;&gt;kdump&lt;/a&gt; crash files.&lt;/p&gt;

&lt;p&gt;I am not going to explain how to set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kdump&lt;/code&gt; and generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmcore&lt;/code&gt;
&lt;sup&gt;&lt;a href=&quot;#ft2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; file since there are plenty of docs around explaining how to do so.
Our focus here is to exemplify a use case for crash. You need to use a debug kernel
to show the warning and you must run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysctl panic_on_warn=1&lt;/code&gt; to generate a
crash dump on warning.&lt;/p&gt;

&lt;p&gt;Assuming you have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmlinux&lt;/code&gt; image and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmcore&lt;/code&gt; dump, you start &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crash&lt;/code&gt; like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# crash /usr/lib/debug/lib/modules/4.18.0-311.rt7.92.el8.test.x86_64+debug/vmlinux vmore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; command shows messages from the kernel ring buffer in case you have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmcore&lt;/code&gt;
file but no log dump. Let’s use the
&lt;a href=&quot;https://crash-utility.github.io/help_pages/bt.html&quot;&gt;bt&lt;/a&gt; command to see the call stack trace:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; bt -s
PID: 31010  TASK: ffff8882024a3500  CPU: 0   COMMAND: &quot;rcu_torture_rea&quot;
 #0 [ffff8881d2067620] machine_kexec+888 at ffffffff8a920d28
 #1 [ffff8881d2067740] __crash_kexec+171 at ffffffff8ac938bb
 #2 [ffff8881d2067858] panic+476 at ffffffff8aa01605
 #3 [ffff8881d2067918] __warn.cold.6+27 at ffffffff8aa018aa
 #4 [ffff8881d2067958] report_bug+412 at ffffffff8c788c8c
 #5 [ffff8881d2067988] do_error_trap+306 at ffffffff8a854542
 #6 [ffff8881d20679d0] do_invalid_op+54 at ffffffff8a854f86
 #7 [ffff8881d20679f0] invalid_op+20 at ffffffff8ca00e04
    [exception RIP: __local_bh_disable_ip+1198]
    RIP: ffffffff8aa1b37e  RSP: ffff8881d2067aa0  RFLAGS: 00010282
    RAX: 0000000000000000  RBX: 0000000000000200  RCX: ffffffff8adbc90e
    RDX: 0000000000000000  RSI: 0000000000000004  RDI: 0000000000000246
    RBP: ffff8881d2067ad8   R8: fffffbfff1d271e2   R9: 0000000000000000
    R10: ffffffff8e938f0b  R11: fffffbfff1d271e1  R12: ffff8882024a3500
    R13: 0000000000000010  R14: ffff8881d2067b98  R15: 0000000000000044
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
 #8 [ffff8881d2067ae0] rcutorture_one_extend+1483 at ffffffffc19f745b [rcutorture]
 #9 [ffff8881d2067b40] rcu_torture_one_read+1763 at ffffffffc19f8033 [rcutorture]
#10 [ffff8881d2067dc8] rcu_torture_reader+578 at ffffffffc19f8762 [rcutorture]
#11 [ffff8881d2067f10] kthread+976 at ffffffff8aa80ed0
#12 [ffff8881d2067f50] ret_from_fork+58 at ffffffff8ca0026a
crash&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, I am using the linux image provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel-rt-debug-debuginfo&lt;/code&gt;
&lt;sup&gt;&lt;a href=&quot;#ft3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; file. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt; option displays the offsets of the functions. By the way,
typing &lt;a href=&quot;https://crash-utility.github.io/help.html&quot;&gt;help&lt;/a&gt; shows a summary of the
available commands, and typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;help &amp;lt;cmd&amp;gt;&lt;/code&gt; shows the documentation for the command
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd&lt;/code&gt;. You can use any gdb commands while using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crash&lt;/code&gt;.  Therefore, to display the variables
we are interested in, set the stack frame to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; function
and print the variables:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; frame 8
crash: prohibited gdb command: frame
crash&amp;gt;  gdb frame 8
crash: prohibited gdb command: frame
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Err, you didn’t think it would be that easy, did you? Sadly, we will need to do
it manually. Before anything else, let’s instruct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crash&lt;/code&gt; to load the debug symbols
for the loadable modules with the
&lt;a href=&quot;https://crash-utility.github.io/help_pages/mod.html&quot;&gt;mod&lt;/a&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; mod -S                                                                                                                                                                                                                                                     
     MODULE       NAME                    SIZE  OBJECT FILE                                                                                                                                                                                                       
ffffffffc04678c0  dm_mod                397312  /usr/.../modules/.../kernel/drivers/md/dm-mod.ko.debug
ffffffffc047ee00  dm_log                 36864  /usr/.../modules/.../kernel/drivers/md/dm-log.ko.debug
ffffffffc0497a80  dm_region_hash         36864  /usr/.../modules/.../kernel/drivers/md/dm-region-hash.ko.debug
ffffffffc04ae300  dm_mirror              65536  /usr/.../modules/.../kernel/drivers/md/dm-mirror.ko.debug
ffffffffc04c6f80  ip_tables              69632  /usr/.../modules/.../kernel/net/ipv4/netfilter/ip_tables.ko.debug
ffffffffc0545900  sysfillrect            28672  /usr/.../modules/.../kernel/drivers/video/fbdev/core/sysfillrect.ko.debug
ffffffffc054c000  syscopyarea            24576  /usr/.../modules/.../kernel/drivers/video/fbdev/core/syscopyarea.ko.debug
ffffffffc055b340  crc32c_intel           24576  /usr/.../modules/.../kernel/arch/x86/crypto/crc32c-intel.ko.debug
ffffffffc056ee40  mgag200                69632  /usr/.../modules/.../kernel/drivers/gpu/drm/mgag200/mgag200.ko.debug
ffffffffc057adc0  ata_generic            20480  /usr/.../modules/.../kernel/drivers/ata/ata_generic.ko.debug
ffffffffc0583680  t10_pi                 20480  /usr/.../modules/.../kernel/block/t10-pi.ko.debug
ffffffffc0595200  mdio                   28672  /usr/.../modules/.../kernel/drivers/net/mdio.ko.debug
ffffffffc05a55c0  ata_piix               61440  /usr/.../modules/.../kernel/drivers/ata/ata_piix.ko.debug
ffffffffc05aa180  libcrc32c              16384  /usr/.../modules/.../kernel/lib/libcrc32c.ko.debug
...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can use the &lt;a href=&quot;https://crash-utility.github.io/help_pages/dis.html&quot;&gt;dis&lt;/a&gt;
command to find out the source line where we call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; dis -l rcutorture_one_extend
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1235
&amp;lt;rcutorture_one_extend&amp;gt;:     data32 data32 data32 xchg %ax,%ax [FTRACE NOP]
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1238
&amp;lt;rcutorture_one_extend+5&amp;gt;:   movabs $0xdffffc0000000000,%rax
&amp;lt;rcutorture_one_extend+15&amp;gt;:  push   %rbp
...
...
...
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/./include/linux/bottom_half.h: 19
&amp;lt;rcutorture_one_extend+1444&amp;gt;:        mov    $0x200,%esi
&amp;lt;rcutorture_one_extend+1449&amp;gt;:        mov    $0xffffffffc19f7434,%rdi
&amp;lt;rcutorture_one_extend+1456&amp;gt;:        callq  0xffffffff8aa1aed0 &amp;lt;__local_bh_disable_ip&amp;gt;
&amp;lt;rcutorture_one_extend+1461&amp;gt;:        jmpq   0xffffffffc19f6f44 &amp;lt;rcutorture_one_extend+180&amp;gt;
&amp;lt;rcutorture_one_extend+1466&amp;gt;:        mov    $0x200,%esi
&amp;lt;rcutorture_one_extend+1471&amp;gt;:        mov    $0xffffffffc19f744a,%rdi
&amp;lt;rcutorture_one_extend+1478&amp;gt;:        callq  0xffffffff8aa1aed0 &amp;lt;__local_bh_disable_ip&amp;gt;
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1264
&amp;lt;rcutorture_one_extend+1483&amp;gt;:        testb  $0x80,-0x30(%rbp)
...
...
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-l&lt;/code&gt; option provides the source code line number information. We see that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1483&lt;/code&gt;
offset is at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture.c:1264&lt;/code&gt; and the instruction above is the call we are
looking for&lt;sup&gt;&lt;a href=&quot;#ft4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. Now we can look at the source code to see the
corresponding line:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;crash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rcutorture_one_extend&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;FILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcutorture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;LINE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1235&lt;/span&gt;

  &lt;span class=&quot;mi&quot;&gt;1230&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1231&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1232&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rcutorture_one_extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1233&lt;/span&gt;                                    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torture_random_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;                                    &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rt_read_seg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rtrsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1235&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1236&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1237&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idxnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1238&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1239&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1240&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statesold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1241&lt;/span&gt;  
  &lt;span class=&quot;mi&quot;&gt;1242&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;WARN_ON_ONCE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1243&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;WARN_ON_ONCE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idxold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_SHIFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1244&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;rtrsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt_readstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newstate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1245&lt;/span&gt;  
  &lt;span class=&quot;mi&quot;&gt;1246&lt;/span&gt;          &lt;span class=&quot;cm&quot;&gt;/*
  1247           * First, put new protection in place to avoid critical-section gap.
  1248           * Disable preemption around the ATOM disables to ensure that
  1249           * in_atomic() is true.
  1250           */&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1251&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_BH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1252&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;local_bh_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1253&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_RBH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1254&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;rcu_read_lock_bh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1255&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_IRQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1256&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;local_irq_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1257&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_PREEMPT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1258&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;preempt_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1259&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_SCHED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1260&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;rcu_read_lock_sched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1261&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;preempt_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1262&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_ATOM_BH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1263&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;local_bh_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1264&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statesnew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RCUTORTURE_RDR_ATOM_RBH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;1265&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;rcu_read_lock_bh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1263&lt;/code&gt; is where  we make the call.&lt;/p&gt;

&lt;p&gt;As promised at the beginning, we will now recover the values of the local variables
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt;. Let’s start by looking at the start of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; function assembly code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; dis -l rcutorture_one_extend
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1235
&amp;lt;rcutorture_one_extend&amp;gt;:     data32 data32 data32 xchg %ax,%ax [FTRACE NOP]
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1238
&amp;lt;rcutorture_one_extend+5&amp;gt;:   movabs $0xdffffc0000000000,%rax
&amp;lt;rcutorture_one_extend+15&amp;gt;:  push   %rbp
&amp;lt;rcutorture_one_extend+16&amp;gt;:  mov    %rsp,%rbp
&amp;lt;rcutorture_one_extend+19&amp;gt;:  push   %r15
&amp;lt;rcutorture_one_extend+21&amp;gt;:  mov    %esi,%r15d
&amp;lt;rcutorture_one_extend+24&amp;gt;:  push   %r14
&amp;lt;rcutorture_one_extend+26&amp;gt;:  mov    %rdi,%r14
&amp;lt;rcutorture_one_extend+29&amp;gt;:  push   %r13
&amp;lt;rcutorture_one_extend+31&amp;gt;:  push   %r12
&amp;lt;rcutorture_one_extend+33&amp;gt;:  push   %rbx
&amp;lt;rcutorture_one_extend+34&amp;gt;:  sub    $0x28,%rsp
&amp;lt;rcutorture_one_extend+38&amp;gt;:  mov    %rdx,-0x48(%rbp)
&amp;lt;rcutorture_one_extend+42&amp;gt;:  mov    %rdi,%rdx
&amp;lt;rcutorture_one_extend+45&amp;gt;:  shr    $0x3,%rdx
&amp;lt;rcutorture_one_extend+49&amp;gt;:  mov    %rcx,-0x38(%rbp)
&amp;lt;rcutorture_one_extend+53&amp;gt;:  movzbl (%rdx,%rax,1),%edx
&amp;lt;rcutorture_one_extend+57&amp;gt;:  mov    %rdi,%rax
&amp;lt;rcutorture_one_extend+60&amp;gt;:  and    $0x7,%eax
&amp;lt;rcutorture_one_extend+63&amp;gt;:  add    $0x3,%eax
&amp;lt;rcutorture_one_extend+66&amp;gt;:  cmp    %dl,%al
&amp;lt;rcutorture_one_extend+68&amp;gt;:  jl     0xffffffffc19f6ede &amp;lt;rcutorture_one_extend+78&amp;gt;
&amp;lt;rcutorture_one_extend+70&amp;gt;:  test   %dl,%dl
&amp;lt;rcutorture_one_extend+72&amp;gt;:  jne    0xffffffffc19f7856 &amp;lt;rcutorture_one_extend+2502&amp;gt;
&amp;lt;rcutorture_one_extend+78&amp;gt;:  mov    (%r14),%r13d
/usr/src/debug/kernel-rt-4.18.0-311.rt7.92.el8.test/linux-4.18.0-311.rt7.92.el8.test.x86_64/kernel/rcu/rcutorture.c: 1239
&amp;lt;rcutorture_one_extend+81&amp;gt;:  mov    %r15d,%r12d
&amp;lt;rcutorture_one_extend+84&amp;gt;:  not    %r12d
&amp;lt;rcutorture_one_extend+87&amp;gt;:  mov    %r13d,%eax
&amp;lt;rcutorture_one_extend+90&amp;gt;:  and    %r13d,%r12d
&amp;lt;rcutorture_one_extend+93&amp;gt;:  not    %eax
&amp;lt;rcutorture_one_extend+95&amp;gt;:  and    %r15d,%eax
&amp;lt;rcutorture_one_extend+98&amp;gt;:  mov    %eax,-0x30(%rbp)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only parameters we care about are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readstate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newstate&lt;/code&gt;.
According to the
&lt;a href=&quot;https://aaronbloomfield.github.io/pdr/book/x86-64bit-ccc-chapter.pdf&quot;&gt;x86_64 calling convention&lt;/a&gt;,
they are passed, respectively, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rdi&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsi&lt;/code&gt; registers. Below is
a commented version of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; function assembly code up
to the part that assigns values to both variables:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;movabs $0xdffffc0000000000,%rax
push   %rbp
mov    %rsp,%rbp  # setup the function stack frame
push   %r15       # save register r15
mov    %esi,%r15d # move newstate to r15d
push   %r14       # save r14
mov    %rdi,%r14  # move readstate to rdi
push   %r13       # save r13
push   %r12       # save r12
push   %rbx       # save rbx
sub    $0x28,%rsp # allocate space for the local variables

#######################################################################
# this part doesn&apos;t interest us
mov    %rdx,-0x48(%rbp)
mov    %rdi,%rdx
shr    $0x3,%rdx
mov    %rcx,-0x38(%rbp)
movzbl (%rdx,%rax,1),%edx
mov    %rdi,%rax
and    $0x7,%eax
add    $0x3,%eax
cmp    %dl,%al
jl     0xffffffffc19f6ede &amp;lt;rcutorture_one_extend+78&amp;gt;
test   %dl,%dl
jne    0xffffffffc19f7856 &amp;lt;rcutorture_one_extend+2502&amp;gt;
#######################################################################

mov    (%r14),%r13d     # move *readstate to r14d
mov    %r15d,%r12d      # move newstate to r12d
not    %r12d            # r12 = ~newstate
mov    %r13d,%eax       # move *readstate to eax
and    %r13d,%r12d      # r12d = *readstate &amp;amp; ~newstate = statesold
not    %eax             # eax = ~*readstate
and    %r15d,%eax       # eax = ~*readstate &amp;amp; newstate = statesnew
mov    %eax,-0x30(%rbp) # statesnew = (int) rbp[-6]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the code above, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt; ends up in the register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r12d&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew&lt;/code&gt;
ends in the position &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rbp-6&lt;/code&gt; (in 64 bits sized chunks) of the stack frame.
We shall start deducing the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew&lt;/code&gt;. We can take advantage
of the option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-f&lt;/code&gt; of the &lt;a href=&quot;https://crash-utility.github.io/help_pages/bt.html&quot;&gt;bt&lt;/a&gt;
command to display the content of the stack frame:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; bt -f
...
 #8 [ffff8881d2067ae0] rcutorture_one_extend at ffffffffc19f745b [rcutorture]
    ffff8881d2067ae8: ffffffff8abc8c10 ffff8881d2067e00
    ffff8881d2067af8: 000000003a40cf78 ffff8881d2067c00
    ffff8881d2067b08: ffff888300000044 ffff8881d2067bd8
    ffff8881d2067b18: ffffffffc1a5f300 ffff8881d2067c28
    ffff8881d2067b28: ffff8881d2067b98 ffff8881d2067d40
    ffff8881d2067b38: ffff8881d2067e00 ffffffffc19f8033
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The stack frame starts at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffff8881d2067b38&lt;/code&gt; (remember the stack grows downwards).
The first position corresponds to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rbp&lt;/code&gt; push at the function preamble.
We then count 6 positions upwards to the right and reach the address
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffff8881d2067b08&lt;/code&gt; whose value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffff888300000044&lt;/code&gt;. Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew&lt;/code&gt; is an
integer, we only count the first 32 bits and we finally find the
value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x44&lt;/code&gt;. If we look at the
&lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git/tree/kernel/rcu/rcutorture.c?h=linux-5.13.y-rt-rebase#n60&quot;&gt;kernel/rcu/rcutorture.c&lt;/a&gt;
source file, we conclude that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesnew = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_ATOM_BH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt; is stored in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r12d&lt;/code&gt; register, but we can’t rely on the register value because
it probably has already been clobbered by one of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; callees.
However, it is saved in some function’s stack frame. Here is the prologue of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt;, the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcutorture_one_extend&lt;/code&gt; callee:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; dis __local_bh_disable_ip
&amp;lt;__local_bh_disable_ip&amp;gt;:     data32 data32 data32 xchg %ax,%ax [FTRACE NOP]
&amp;lt;__local_bh_disable_ip+5&amp;gt;:   push   %rbp
&amp;lt;__local_bh_disable_ip+6&amp;gt;:   mov    %rsp,%rbp
&amp;lt;__local_bh_disable_ip+9&amp;gt;:   push   %r15
&amp;lt;__local_bh_disable_ip+11&amp;gt;:  push   %r14
&amp;lt;__local_bh_disable_ip+13&amp;gt;:  push   %r13
&amp;lt;__local_bh_disable_ip+15&amp;gt;:  push   %r12
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Indeed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt; is saved in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt; stack frame, more
precisely in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rbp-4&lt;/code&gt;. Below is the function stack frame:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crash&amp;gt; bt -f
...
 #7 [ffff8881d20679f0] invalid_op at ffffffff8ca00e04
    [exception RIP: __local_bh_disable_ip+1198]
    RIP: ffffffff8aa1b37e  RSP: ffff8881d2067aa0  RFLAGS: 00010282
    RAX: 0000000000000000  RBX: 0000000000000200  RCX: ffffffff8adbc90e
    RDX: 0000000000000000  RSI: 0000000000000004  RDI: 0000000000000246
    RBP: ffff8881d2067ad8   R8: fffffbfff1d271e2   R9: 0000000000000000
    R10: ffffffff8e938f0b  R11: fffffbfff1d271e1  R12: ffff8882024a3500
    R13: 0000000000000010  R14: ffff8881d2067b98  R15: 0000000000000044
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
    ffff8881d20679f8: 0000000000000044 ffff8881d2067b98 
    ffff8881d2067a08: 0000000000000010 ffff8882024a3500 
    ffff8881d2067a18: ffff8881d2067ad8 0000000000000200 
    ffff8881d2067a28: fffffbfff1d271e1 ffffffff8e938f0b 
    ffff8881d2067a38: 0000000000000000 fffffbfff1d271e2 
    ffff8881d2067a48: 0000000000000000 ffffffff8adbc90e 
    ffff8881d2067a58: 0000000000000000 0000000000000004 
    ffff8881d2067a68: 0000000000000246 ffffffffffffffff 
    ffff8881d2067a78: ffffffff8aa1b37e 0000000000000010 
    ffff8881d2067a88: 0000000000010282 ffff8881d2067aa0 
    ffff8881d2067a98: 0000000000000018 ffff8881d2067e00 
    ffff8881d2067aa8: ffffffffc19f744a ffff8881d2067bd8 
    ffff8881d2067ab8: 0000000000000010 0000000000000010 
    ffff8881d2067ac8: ffff8881d2067b98 0000000000000044 
    ffff8881d2067ad8: ffff8881d2067b38 ffffffffc19f745b
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I guess you can see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold&lt;/code&gt; location is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xffff8881d2067ab8&lt;/code&gt; and
its value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10&lt;/code&gt;. If we do the same exercise of looking for the corresponding
macro(s) definition(s) for the value, we discover that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;statesold = RCUTORTURE_RDR_SCHED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/julia-denham-4828a5120/&quot;&gt;Julia Denham&lt;/a&gt; for
taking the time to review this post!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a name=&quot;ft1&quot;&gt;1&lt;/a&gt;: the watchful reader may find some inconsistencies
among the line numbers reported in the log and in the git tree. This is because
I am debugging the
&lt;a href=&quot;https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux&quot;&gt;RHEL&lt;/a&gt;
8 kernel.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft2&quot;&gt;2&lt;/a&gt;: the name of the crash file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kdump&lt;/code&gt; generates.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft3&quot;&gt;3&lt;/a&gt;: notice that I am using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rt-debug&lt;/code&gt; kernel to reproduce the problem.
This bug only manifests in the realtime kernel. Be sure to use the debuginfo package
corresponding to your kernel.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft4&quot;&gt;4&lt;/a&gt;: bear in mind that the call stack entries indicate the return addresses.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;ft5&quot;&gt;5&lt;/a&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local_bh_disable&lt;/code&gt; is an inline function that calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__local_bh_disable_ip&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;local_bh_disable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;__local_bh_disable_ip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_THIS_IP_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOFTIRQ_DISABLE_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 24 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/kernel-crashes/</link>
        <guid isPermaLink="true">https://walac.github.io/kernel-crashes/</guid>
        
        <category>linux</category>
        
        <category>kernel</category>
        
        <category>crash</category>
        
        
        <category>kernel</category>
        
      </item>
    
      <item>
        <title>NUIPreview: a Visual Studio extension to build Tizen.NUI graphical interfaces</title>
        <description>&lt;p&gt;As the last project of 2020, I and some other co-workers were assigned the
task of creating a prototype for a graphical user interface preview Visual
Studio extension for the
&lt;a href=&quot;https://docs.tizen.org/application/dotnet/guides/nui/overview/&quot;&gt;NUI&lt;/a&gt;
graphics toolkit. Notice the extension is for
&lt;a href=&quot;https://visualstudio.microsoft.com/&quot;&gt;Visual Studio&lt;/a&gt;, not
&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is the programmer create the user interface in a
&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/desktop/wpf/fundamentals/xaml?view=netdesktop-5.0#:~:text=is under construction.-,What is XAML,NET Core app.&quot;&gt;XAML&lt;/a&gt;
file and the plugin displays the preview of the user interface. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NUI&lt;/code&gt; already
has &lt;a href=&quot;https://docs.tizen.org/application/dotnet/guides/nui/xaml/xaml-support-for-tizen-nui/&quot;&gt;some support&lt;/a&gt;
for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XAML&lt;/code&gt; standard.&lt;/p&gt;

&lt;p&gt;For parsing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XAML&lt;/code&gt; file, &lt;a href=&quot;https://github.com/lauromoura&quot;&gt;@lauromoura&lt;/a&gt;
found the &lt;a href=&quot;https://github.com/OmniGUI/OmniXAML&quot;&gt;OmniXaml&lt;/a&gt; library. Although not
maintained anymore, the library is pretty complete. Our initial idea was to make
the window show the result integrated with Visual Studio, but as NUI creates its
own Window and message loop, we had to take another approach. The basic
architecture is as follows: when the user click in the menu to show the preview,
we start a thread in which we create the NUI Window and run the message loop. We also
start a timer that periodically polls the active document; if it is a XAML file
and we can parse it successfully, we update the UI.&lt;/p&gt;

&lt;p&gt;One particular detail is that Visual Studio is a 32 bits executable, so all the
&lt;a href=&quot;https://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt; libraries and
their dependencies must be compiled in 32 bits. As &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DALi&lt;/code&gt; is contantly evolving,
we created a branch in our own fork to make sure we can keep the plugin development
without being surprised by bugs introduced by new commits.&lt;/p&gt;

&lt;h1 id=&quot;building-dali-for-32-bits-windows&quot;&gt;Building DALi for 32 bits Windows&lt;/h1&gt;

&lt;p&gt;First, you have to make sure all &lt;a href=&quot;https://github.com/Microsoft/vcpkg&quot;&gt;vcpkg&lt;/a&gt; dependencies
are installed with their 32 bits variant.
That’s the default in vcpkg last time I checked, but you can also add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:x86-windows&lt;/code&gt; suffix
for each package name.&lt;/p&gt;

&lt;p&gt;That said, download our fork of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DALi&lt;/code&gt; libraries:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; vsix git://github.com/expertisesolutions/dali-core
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; vsix git://github.com/expertisesolutions/dali-adaptor
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; vsix git://github.com/expertisesolutions/dali-toolkit
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; vsix git://github.com/expertisesolutions/dali-csharp-binder
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; vsix git://github.com/expertisesolutions/tizenfx-stub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You also need the
&lt;a href=&quot;https://github.com/dalihub/windows-dependencies/&quot;&gt;windows-dependencies&lt;/a&gt;
repository. To build the libraries, you can use the following batch script:&lt;/p&gt;

&lt;div class=&quot;language-bat highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;base_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;c&lt;/span&gt;:\work
&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;common_args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-g &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Visual Studio 16 2019&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-A &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Win32&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DCMAKE&lt;/span&gt;_INSTALL_PREFIX&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\dali&lt;span class=&quot;na&quot;&gt;-env &lt;/span&gt;\
&lt;span class=&quot;na&quot;&gt;-DCMAKE&lt;/span&gt;_TOOLCHAIN_FILE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\vcpkg\scripts\buildsystems\vcpkg.cmake &lt;span class=&quot;na&quot;&gt;-DCMAKE&lt;/span&gt;_BUILD_TYPE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;Debug&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_DEBUG&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-Wno-dev

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;REM window-dependencies&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\windows&lt;span class=&quot;na&quot;&gt;-dependencies&lt;/span&gt;\build\
&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;REM dali-core&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\dali&lt;span class=&quot;na&quot;&gt;-core&lt;/span&gt;\build\tizen
&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_PKG_CONFIGURE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_LINK_TEST&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DINSTALL&lt;/span&gt;_CMAKE_MODULES&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ON&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;REM dali-adaptor&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\dali&lt;span class=&quot;na&quot;&gt;-adaptor&lt;/span&gt;\build\tizen
&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_PKG_CONFIGURE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_LINK_TEST&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DINSTALL&lt;/span&gt;_CMAKE_MODULES&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DPROFILE&lt;/span&gt;_LCASE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;windows&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;REM dali-toolkit&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\dali&lt;span class=&quot;na&quot;&gt;-toolkit&lt;/span&gt;\build\tizen
&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_PKG_CONFIGURE&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DENABLE&lt;/span&gt;_LINK_TEST&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DINSTALL&lt;/span&gt;_CMAKE_MODULES&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-DUSE&lt;/span&gt;_DEFAULT_RESOURCE_DIR&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;OFF&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;-j&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;REM dali-csharp-binder&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\dali&lt;span class=&quot;na&quot;&gt;-csharp-binder&lt;/span&gt;\build\tizen
&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--verbose --config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;tizenfx&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-stub
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;\tizenfx&lt;span class=&quot;na&quot;&gt;-stub
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rd&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/Q /S &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;-windows
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%common_args%&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--build &lt;/span&gt;. &lt;span class=&quot;na&quot;&gt;--target &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--verbose --config &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;:error&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%base_dir%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice it assumes you have the vcpkg and the repositories under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\work&lt;/code&gt;.
You can tweak the script for your own directory structure.&lt;/p&gt;

&lt;p&gt;You also need to build &lt;a href=&quot;https://opensource.google/projects/angle&quot;&gt;angle&lt;/a&gt;.
To build it you can follow the
&lt;a href=&quot;https://chromium.googlesource.com/angle/angle/+/refs/heads/master/doc/DevSetup.md&quot;&gt;official documentation&lt;/a&gt;,
but before running the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;autoninja&lt;/code&gt; command to compile it, you have to
run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gn args &amp;lt;output directory&amp;gt;&lt;/code&gt; and set the following variables:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;angle_enable_d3d11 = false
target_cpu = &quot;x86&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To make redistribution of the plugin easier, we ship the
&lt;a href=&quot;https://github.com/expertisesolutions/NUIPreview&quot;&gt;NUIPreview repository&lt;/a&gt;
with all
&lt;a href=&quot;https://github.com/expertisesolutions/NUIPreview/tree/master/NUIPreview/deps&quot;&gt;DLL dependencies&lt;/a&gt;, so
you don’t need to worry about compiling them.&lt;/p&gt;

&lt;h1 id=&quot;running-the-plugin&quot;&gt;Running the plugin&lt;/h1&gt;

&lt;p&gt;Here is a demo of how the plugin behaves:&lt;/p&gt;

&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/67ccJSP7Vi8&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Of course, this is just a prototype. You check the source code in the
&lt;a href=&quot;https://github.com/expertisesolutions/NUIPreview&quot;&gt;repository&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Dec 2020 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/tizen-nui-vsix/</link>
        <guid isPermaLink="true">https://walac.github.io/tizen-nui-vsix/</guid>
        
        <category>tizen</category>
        
        <category>C#</category>
        
        
        <category>tizen</category>
        
      </item>
    
      <item>
        <title>Highway to hell: C++ enums and bit fields</title>
        <description>&lt;p&gt;C++ enums historically gave me some headaches due to the fact that compilers are free to choose the size
of the type for whatever criteria they think. This makes particularly hard to write portable code among
compilers from ABI point of view (Visual C++ vs C++ Builder, anyone?).&lt;/p&gt;

&lt;p&gt;Some days ago I was debugging a problem with &lt;a href=&quot;https://github.com/dalihub/dali-toolkit&quot;&gt;dali-toolkit&lt;/a&gt;
and the enum story scalated to another level.&lt;/p&gt;

&lt;p&gt;Let me give you some background: &lt;a href=&quot;https://github.com/dalihub/dali-toolkit&quot;&gt;dali-toolkit&lt;/a&gt; loads textures
using a background worker thread that is responsible to load the image files to memory. I was looking
why some textures didn’t load in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Windows&lt;/code&gt;. To make the asynchronous loading possible it implements
a small state machine and it keeps all information about the texture in a type called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextureInfo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a partial definition of the structure:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TextureInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// ....&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoadState&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loadState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;///&amp;lt; The load state showing the load progress of the Texture&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FittingMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fittingMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;///&amp;lt; The requested FittingMode&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Dali&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SamplingMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;samplingMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;///&amp;lt; The requested SamplingMode&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;StorageType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;storageType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;///&amp;lt; CPU storage / GPU upload;&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// ....&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All these custom types are enums defined elsewhere. Yes, you read right, enums + bit fields, what
possibly can go wrong? To illustrate the root cause of the bug, let’s write a toy sample:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Cat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Horse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Turtle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BorderCollie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;GoldenRetriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;GermanShepard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Husky&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;No&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnimalInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adopted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adopted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GermanShepard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, using &lt;a href=&quot;https://godbolt.org&quot;&gt;godbolt&lt;/a&gt;, we can view the assembly code generated by different compilers.
In particular, let’s look at the assembly code for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; function. Firstly, the the gcc generated
code. I added comments to the parts interesting to us:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        lea     rax, [rbp-8]
        mov     ecx, 1
        mov     edx, 2
        mov     esi, 1
        mov     rdi, rax
        call    AnimalInfo::AnimalInfo(Animal, Breed, Adopted)
        movzx   eax, BYTE PTR [rbp-8] // load the information
        shr     al, 2   	// breed is in the bits 2 and 3, so shift right 2 bits
        and     eax, 3  	// breed is only two bits long
        movzx   eax, al  	// eax = breed value
        mov     DWORD PTR [rbp-4], eax // store it in our variable
        mov     eax, 4    // AnimalInfo is 4 bytes long
        leave
        ret
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is clang. It uses different registers but is essentially the same code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     dword ptr [rbp - 4], 0
        lea     rdi, [rbp - 8]
        mov     eax, 1
        mov     esi, eax
        mov     edx, 2
        mov     ecx, eax
        call    AnimalInfo::AnimalInfo(Animal, Breed, Adopted)
        mov     r8b, byte ptr [rbp - 8]
        shr     r8b, 2
        and     r8b, 3
        movzx   eax, r8b
        mov     dword ptr [rbp - 12], eax
        mov     eax, 4
        add     rsp, 16
        pop     rbp
        ret
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now the msvc compiler:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main PROC
$LN3:
  sub rsp, 56 ; 00000038H
  mov r9d, 1
  mov r8d, 2
  mov edx, 1
  lea rcx, QWORD PTR animal$[rsp]
  call AnimalInfo::AnimalInfo(Animal,Breed,Adopted) ; AnimalInfo::AnimalInfo
  mov eax, DWORD PTR animal$[rsp]
  shl eax, 28
  sar eax, 30 // OH NO! SIGNED SHIFT!!!
  mov DWORD PTR breed$[rsp], eax
  mov eax, 4
  add rsp, 56 ; 00000038H
  ret 0
main ENDP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before commenting about the bug generated by msvc, let me praise the compiler optimizer,
it got the breed value in two instructions, while clang and gcc needed three.
Very smart! Too bad that code is wrong. I think it is better to undestand the issue if we
view the bit layout of the word holded by AnimalInfo:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	-------------------------------------
	|  31-5  |    4    |  3-2  |  1-0   |
	-------------------------------------
	| Unused | Adopted | Breed | Animal |
	-------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, the code shifts 28 bits to left, moving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Breed&lt;/code&gt; to the bits 31 and 30, then it
shifts 30 bits to the right, but it does a signed shift, filling the
shifted bits with the value of the most significant bit. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Breed&lt;/code&gt; value is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GermanShepard&lt;/code&gt;, which is 2. So, when we shift left, the bit 31 will hold the value
1, and when we shift right, we end up with the final value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xfffffffe&lt;/code&gt;! The reason this happens
is because msvc assumes the enum is a signed integer by default and, combined with
the use of bit fields, yields the bug. This is precisely what happened in
&lt;a href=&quot;https://github.com/dalihub/dali-toolkit&quot;&gt;dali-toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once we understood the problem, we can solve it easily by forcing the enum to an unsigned integer:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Animal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Cat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Horse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Turtle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Breed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BorderCollie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;GoldenRetriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;GermanShepard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Husky&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Adopted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;No&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnimalInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adopted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adopted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Animal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Breed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GermanShepard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adopted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnimalInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now the generated code does what it is supposed to do:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;main PROC
$LN3:
  sub rsp, 56 ; 00000038H
  mov r9d, 1
  mov r8d, 2
  mov edx, 1
  lea rcx, QWORD PTR animal$[rsp]
  call AnimalInfo::AnimalInfo(Animal,Breed,Adopted) ; AnimalInfo::AnimalInfo
  mov eax, DWORD PTR animal$[rsp]
  shr eax, 2
  and eax, 3
  mov DWORD PTR breed$[rsp], eax
  mov eax, 4
  add rsp, 56 ; 00000038H
  ret 0
main ENDP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 25 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/curious-bug-enum-bitfield/</link>
        <guid isPermaLink="true">https://walac.github.io/curious-bug-enum-bitfield/</guid>
        
        <category>cpp</category>
        
        
        <category>cpp</category>
        
      </item>
    
      <item>
        <title>Building DALi library for Windows</title>
        <description>&lt;p&gt;Since I left &lt;a href=&quot;https://mozilla.org&quot;&gt;Mozilla&lt;/a&gt; I came back to my old days as a
C/C++ developer. One of the projects I am working on is porting the
&lt;a href=&quot;https://docs.tizen.org/application/dotnet/guides/nui/overview/&quot;&gt;Tizen.NUI&lt;/a&gt; API
to Windows. &lt;a href=&quot;https://docs.tizen.org/application/dotnet/guides/nui/overview/&quot;&gt;Tizen.NUI&lt;/a&gt;
itself is written in C#, so it doesn’t require any major effort to run on Windows,
but it is heavily based on
&lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;, and there
where the job lies. &lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;
kind of works on Windows already, but I caught several bugs affecting 64 bits. You
can refer to the pull requests to get details on what was wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;,
doesn’t belong to a single repo, actually. On top of
&lt;a href=&quot;https://github.com/dalihub/dali-core/&quot;&gt;dali-core&lt;/a&gt; we have
&lt;a href=&quot;https://github.com/dalihub/dali-adaptor&quot;&gt;dali-adaptor&lt;/a&gt; and
&lt;a href=&quot;https://github.com/dalihub/dali-toolkit&quot;&gt;dali-toolkit&lt;/a&gt;, not to mention the sample
&lt;a href=&quot;https://github.com/dalihub/dali-demos/&quot;&gt;applications&lt;/a&gt;. This post is a step by step
guide to build &lt;a href=&quot;https://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;
on Windows.&lt;/p&gt;

&lt;h1 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h1&gt;

&lt;p&gt;To build and install &lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;
you will need:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://visualstudio.microsoft.com/vs/community/&quot;&gt;Visual Studio 2019&lt;/a&gt; (Community Edition is fine)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitforwindows.org/&quot;&gt;git&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Microsoft/vcpkg/&quot;&gt;vcpkg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;building-windows-dependencies&quot;&gt;Building Windows dependencies&lt;/h1&gt;

&lt;p&gt;After the dependencies installed, you need the
&lt;a href=&quot;https://github.com/dalihub/windows-dependencies&quot;&gt;windows-dependencies&lt;/a&gt; repository.
Run the following commands in a subfolder that will host the DALi repos:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi&amp;gt;git clone https://github.com/dalihub/windows-dependencies
C:\DALi&amp;gt;set VCPKG_FOLDER=C:\DALi
C:\DALi&amp;gt;set DALI_ENV_FOLDER=C:\DALi\dali-env
C:\DALi&amp;gt;cd windows-dependencies\build
C:\DALi\windows-dependencies\build&amp;gt;mkdir build
C:\DALi\windows-dependencies\build&amp;gt;cd build
C:\DALi\windows-dependencies\build\build&amp;gt;cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=%VCPKG_FOLDER%/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=%DALI_ENV_FOLDER% ..
C:\DALi\windows-dependencies\build\build&amp;gt;cmake --build . --target install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DALI_ENV_FOLDER&lt;/code&gt; is the output directory where the artifacts generated are installed.&lt;/p&gt;

&lt;h1 id=&quot;building-the-dali-libraries&quot;&gt;Building the DALi libraries&lt;/h1&gt;

&lt;p&gt;Building the DALi libraries (&lt;a href=&quot;https://github.com/dalihub/dali-core/&quot;&gt;dali-core&lt;/a&gt;,
&lt;a href=&quot;https://github.com/dalihub/dali-adaptor/&quot;&gt;dali-adaptor&lt;/a&gt; and
&lt;a href=&quot;https://github.com/dalihub/dali-toolkit/&quot;&gt;dali-toolkit&lt;/a&gt;) is straightforward and
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; of each library describes the steps in more detail. Here
I am just giving you the sequence of commands to build them. If you want to know
more details, you can refer to each library documentation.&lt;/p&gt;

&lt;h2 id=&quot;dali-core&quot;&gt;dali-core&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi&amp;gt;git clone https://github.com/dalihub/dali-core/
C:\DALi&amp;gt;cd dali-core\build\tizen
C:\DALi\dali-core\build\tizen&amp;gt;mkdir build
C:\DALi\dali-core\build\tizen&amp;gt;cd build
C:\DALi\dali-core\build\tizen\build&amp;gt;cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=%VCPKG_FOLDER%/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DENABLE_LINK_TEST=OFF -DCMAKE_INSTALL_PREFIX=%DALI_ENV_FOLDER% -DINSTALL_CMAKE_MODULES=ON -Wno-dev ..
C:\DALi\dali-core\build\tizen\build&amp;gt;cmake --build . --target install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;dali-adaptor&quot;&gt;dali-adaptor&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi&amp;gt;%VCPKG_FOLDER%\vcpkg\vcpkg.exe install pthreads:x64-windows
C:\DALi&amp;gt;git clone https://github.com/dalihub/dali-adaptor/
C:\DALi&amp;gt;cd dali-adaptor\build\tizen
C:\DALi\dali-adaptor\build\tizen&amp;gt;mkdir build
C:\DALi\dali-adaptor\build\tizen&amp;gt;cd build
C:\DALi\dali-adaptor\build\tizen\build&amp;gt;cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=%VCPKG_FOLDER%/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DENABLE_LINK_TEST=OFF -DCMAKE_INSTALL_PREFIX=%DALI_ENV_FOLDER% -DINSTALL_CMAKE_MODULES=ON -DPROFILE_LCASE=windows -Wno-dev ..
C:\DALi\dali-adaptor\build\tizen\build&amp;gt;cmake --build . --target install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;dali-toolkit&quot;&gt;dali-toolkit&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi&amp;gt;git clone https://github.com/dalihub/dali-toolkit/
C:\DALi&amp;gt;cd dali-toolkit\build\tizen
C:\DALi\dali-toolkit\build\tizen&amp;gt;mkdir build
C:\DALi\dali-toolkit\build\tizen&amp;gt;cd build
C:\DALi\dali-toolkit\build\tizen\build&amp;gt;cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=%VCPKG_FOLDER%/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DENABLE_LINK_TEST=OFF -DCMAKE_INSTALL_PREFIX=%DALI_ENV_FOLDER% -DINSTALL_CMAKE_MODULES=ON -DUSE_DEFAULT_RESOURCE_DIR=ON -Wno-dev ..
C:\DALi\dali-toolkit\build\tizen\build&amp;gt;cmake --build . --target install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;dali-demo&quot;&gt;dali-demo&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dalihub/dali-demo/&quot;&gt;dali-demo&lt;/a&gt; contains a series of sample applications
that you can try to test if your installation is ok. The procedure to build and install
these apps are the same as for the libraries:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi&amp;gt;git clone https://github.com/dalihub/dali-demo/
C:\DALi&amp;gt;cd dali-demo\build\tizen
C:\DALi\dali-demo\build\tizen&amp;gt;mkdir build
C:\DALi\dali-demo\build\tizen&amp;gt;cd build
C:\DALi\dali-demo\build\tizen&amp;gt;cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=%VCPKG_FOLDER%/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DINTERNATIONALIZATION=OFF -DCMAKE_INSTALL_PREFIX=%DALI_ENV_FOLDER% -Wno-dev ..
C:\DALi\dali-demo\build\tizen\build&amp;gt;cmake --build . --target install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;running&quot;&gt;Running&lt;/h1&gt;

&lt;p&gt;If everything was ok, your binaries should reside inside inside the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DALI_ENV_FOLDER&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;
depends on &lt;a href=&quot;https://chromium.googlesource.com/angle/angle&quot;&gt;libANGLE&lt;/a&gt;,
an OpenGL ES library that translates OpenGL calls to one of several supported
backends. On Windows, the default backend is Direct3D 11. I was having
problems with the D3D11 backend on my machine when trying to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DALi&lt;/code&gt;
sample applications. What I did was build &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libANGLE&lt;/code&gt; disabling the D3D11
backend, falling back to Direct X 9. The
&lt;a href=&quot;https://chromium.googlesource.com/angle/angle/+/refs/heads/master/doc/DevSetup.md&quot;&gt;build instructions&lt;/a&gt;
tell how to disable the D3D11 backend.&lt;/p&gt;

&lt;p&gt;With all set, you can run a sample application:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\DALi\dali-env\bin&amp;gt;hello-world.example.exe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the day I write this post, I have some patches merged in the
&lt;a href=&quot;ttps://docs.tizen.org/application/native/guides/ui/dali/&quot;&gt;DALi&lt;/a&gt;
repos and others are pending to review. If you are experiencing crashes
you may want to give a look at the open pull requests and apply
some of them.&lt;/p&gt;
</description>
        <pubDate>Wed, 05 Aug 2020 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/build-dali/</link>
        <guid isPermaLink="true">https://walac.github.io/build-dali/</guid>
        
        <category>windows</category>
        
        <category>dali</category>
        
        
        <category>dali</category>
        
      </item>
    
      <item>
        <title>Running packet.net images in qemu</title>
        <description>&lt;p&gt;For the past months, I have been working on adding Taskcluster support
for &lt;a href=&quot;https://packet.com&quot;&gt;packet.net&lt;/a&gt; cloud provider. The reason for that
is to get faster Firefox for Android CI tests. Tests showed that jobs run
up to 4x faster on bare metal machines than EC2.&lt;/p&gt;

&lt;p&gt;I set up 25 machines to run a small subset of the production tasks, and so
far results are excellent. The problem is that those machines are up 24/7 and there
is no dynamic provisioning. If we need more machines, I have to manually change
the &lt;a href=&quot;https://www.terraform.io&quot;&gt;terraform&lt;/a&gt; script to scale it up. We need a smart
way to do that. We are going to build something similar as
&lt;a href=&quot;https://github.com/taskcluster/aws-provisioner&quot;&gt;aws-provisioner&lt;/a&gt;. However,
we need a custom &lt;strong&gt;packet.net&lt;/strong&gt; image to speed up instance startup.&lt;/p&gt;

&lt;p&gt;The problem is that if you can’t ssh into the machine, there is no way to get
access to it to see what’s wrong. In this post,l I am going to show how you can
run a packet image locally with &lt;a href=&quot;https://www.qemu.org/&quot;&gt;qemu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find documentation about creating custom packet images
&lt;a href=&quot;https://support.packet.com/kb/articles/custom-images&quot;&gt;here&lt;/a&gt; and
&lt;a href=&quot;https://github.com/packethost/packet-images/blob/master/README.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s create a sample image for the post. After you clone the
&lt;a href=&quot;https://github.com/packethost/packet-images&quot;&gt;packet-images repo&lt;/a&gt;, run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./tools/build.sh -d ubuntu_14_04 -p t1.small.x86 -a x86_64 -b ubuntu_14_04-t1.small.x86-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This creates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image.tar.gz&lt;/code&gt; file, which is your packet image.
The goal of this post is not to guide you on creating your custom image; you can refer
to the documentation linked above for this. The goal here is, once you have your
image, how you can run it locally with &lt;a href=&quot;https://www.qemu.org/&quot;&gt;qemu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first step is to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu&lt;/code&gt; disk to install the image into it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ qemu-img create -f raw linux.img 10G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command creates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raw&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu&lt;/code&gt; image. We now need to create a disk partition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cfdisk linux.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dos&lt;/code&gt; for the partition table, create a single primary partition and
make it bootable. We now need to create a loop device to handle our image:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo losetup -Pf linux.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-f&lt;/code&gt; option looks for the first free loop device for attachment to the image file.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-P&lt;/code&gt; option instructs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;losetup&lt;/code&gt; to read the partition table and create a loop
device for each partition found; this avoids we having to play with disk
offsets. Now let’s find our loop device:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo losetup -l
NAME        SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE                                         DIO LOG-SEC
/dev/loop1          0      0         1  1 /var/lib/snapd/snaps/gnome-calculator_260.snap      0     512
/dev/loop8          0      0         1  1 /var/lib/snapd/snaps/gtk-common-themes_818.snap     0     512
/dev/loop6          0      0         1  1 /var/lib/snapd/snaps/core_5662.snap                 0     512
/dev/loop4          0      0         1  1 /var/lib/snapd/snaps/gtk-common-themes_701.snap     0     512
/dev/loop11         0      0         1  1 /var/lib/snapd/snaps/gnome-characters_139.snap      0     512
/dev/loop2          0      0         1  1 /var/lib/snapd/snaps/gnome-calculator_238.snap      0     512
/dev/loop0          0      0         1  1 /var/lib/snapd/snaps/gnome-logs_45.snap             0     512
/dev/loop9          0      0         1  1 /var/lib/snapd/snaps/core_6034.snap                 0     512
/dev/loop7          0      0         1  1 /var/lib/snapd/snaps/gnome-characters_124.snap      0     512
/dev/loop5          0      0         1  1 /var/lib/snapd/snaps/gnome-3-26-1604_70.snap        0     512
/dev/loop12         0      0         0  0 /home/walac/work/packet-images/linux.img            0     512
/dev/loop3          0      0         1  1 /var/lib/snapd/snaps/gnome-system-monitor_57.snap   0     512
/dev/loop10         0      0         1  1 /var/lib/snapd/snaps/gnome-3-26-1604_74.snap        0     512
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We see that our loop device is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/loop12&lt;/code&gt;. If we look in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls -l /dev/loop12*
brw-rw---- 1 root   7, 12 Dec 17 10:39 /dev/loop12
brw-rw---- 1 root 259,  0 Dec 17 10:39 /dev/loop12p1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We see that, thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-P&lt;/code&gt; option, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;losetup&lt;/code&gt; created the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loop12p1&lt;/code&gt;
device for the partition we have. It is time to set up the filesystem:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo mkfs.ext4 -b 1024 /dev/loop12p1 
mke2fs 1.44.4 (18-Aug-2018)
Discarding device blocks: done                            
Creating filesystem with 10484716 1k blocks and 655360 inodes
Filesystem UUID: 2edfe9f2-7e90-4c35-80e2-bd2e49cad251
Superblock backups stored on blocks: 
        8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553, 
        1024001, 1990657, 2809857, 5120001, 5971969

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (65536 blocks): done
Writing superblocks and filesystem accounting information: done     
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, finally we can mount our device and extract the image to it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir mnt
$ sudo mount /dev/loop12p1 mnt/
$ sudo tar -xzf image.tar.gz -C mnt/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last step is to install the bootloader. As we are running an Ubuntu image,
we will use &lt;a href=&quot;https://www.gnu.org/software/grub/manual/grub/grub.html&quot;&gt;grub2&lt;/a&gt;
for that.&lt;/p&gt;

&lt;p&gt;Firstly we need to install grub in the boot sector:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo grub-install --boot-directory mnt/boot/ /dev/loop12
Installing for i386-pc platform.
Installation finished. No error reported.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice we point to the boot directory of our image. Next, we have to
generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grub.cfg&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd mnt/
$ for i in /proc /dev /sys; do sudo mount -B $i .$i; done
$ sudo chroot .
# cd /etc/grub.d/
# chmod -x 30_os-prober
# update-grub
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
Found linux image: /boot/vmlinuz-3.13.0-123-generic
Found initrd image: /boot/initrd.img-3.13.0-123-generic
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We &lt;em&gt;bind mount&lt;/em&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/sys&lt;/code&gt; host mount points inside the Ubuntu image,
then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chroot&lt;/code&gt; into it. Next, to avoid grub creating entries for our host OSes, we disable the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;30_os-prober&lt;/code&gt; script.  Finally we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-grub&lt;/code&gt; and it creates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/grub/grub.cfg&lt;/code&gt; file.
Now the only thing left is cleanup:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# exit
$ for i in dev/ sys/ proc/; do sudo umount $i; done
$ cd ..
$ sudo umount mnt/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The commands are self explanatory. Now let’s run our image:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo qemu-system-x86_64 -enable-kvm -hda /dev/loop12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/qemu.png&quot; alt=&quot;qemu&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And that’s it, you now can run your packet image locally!&lt;/p&gt;
</description>
        <pubDate>Fri, 14 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/booting-packet-images-qemu/</link>
        <guid isPermaLink="true">https://walac.github.io/booting-packet-images-qemu/</guid>
        
        <category>qemu</category>
        
        <category>linux</category>
        
        <category>taskcluster</category>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>A tale of my first Go patch</title>
        <description>&lt;p&gt;For the last year I have been using the &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt;
programming language, working on the implementation of the
&lt;a href=&quot;https://github.com/taskcluster/taskcluster-worker&quot;&gt;taskcluster-worker&lt;/a&gt;
project.  If you want to learn more about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster-worker&lt;/code&gt;, you can
read &lt;a href=&quot;https://walac.github.io/taskcluster-worker-macosx-engine/&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster-worker&lt;/code&gt; task payload, there is a field called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;command&lt;/code&gt;,
that specifies the command the task must run. Through a configuration file,
you can specify either the spawned command should run as the current user
or to run the command with a newly created user. The pseudo code bellow
illustrates how this works:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createUser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CurrentUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;RunCommand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createUser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DeleteUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our first production use for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster-worker&lt;/code&gt; it to run Firefox automated
tests inside the OSX environment. We began configuring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster-worker&lt;/code&gt; to
run each task with a new user to provide some kind of task isolation, but it
didn’t work well. Some tests, as you might wonder, require we run the browser
UI inside a desktop session. To allow this, the taskcluster-worker daemon runs
as a
&lt;a href=&quot;https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html&quot;&gt;Launch Agent&lt;/a&gt;.
The problem is that the test itself runs as a different user, under the desktop
session owned by the taskcluster-worker user. As the user that runs Firefox is
different from the user owning the desktop session, the tests weren’t allowed
to execute several operations, like clipboard copy/paste. Because of this that
we introduced the option to run the test as the current user.&lt;/p&gt;

&lt;p&gt;When implementing the option to run tasks as the current user, I found
a subtle problem with Go process creation package, described next.&lt;/p&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The problem&lt;/h1&gt;

&lt;p&gt;The &lt;a href=&quot;https://golang.org/pkg/os/exec/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os/exec&lt;/code&gt;&lt;/a&gt; package allows you to spawn
new processes. For example, the following code will spawn the
&lt;a href=&quot;https://linux.die.net/man/1/echo&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo&lt;/code&gt;&lt;/a&gt; command and
print the “hello-world” string:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;os/exec&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;echo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello-world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we use the &lt;a href=&quot;https://golang.org/pkg/os/exec/#Command&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Command&lt;/code&gt;&lt;/a&gt; function to
create a &lt;a href=&quot;https://golang.org/pkg/os/exec/#Cmd&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cmd&lt;/code&gt;&lt;/a&gt; structure. We then connect
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt; channels of the child process to the parent process
and spawn the new process. It runs as expected:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go run echo.go
hello-world
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So far so good. You can also set the user in which the process will run.
Let’s demonstrate it by expliciting setting the current user as the user
account of the child process:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;os/exec&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;os/user&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;strconv&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;syscall&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strconv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;gid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strconv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;echo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello-world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SysProcAttr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SysProcAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Credential&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Credential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Uid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Gid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec.Cmd&lt;/code&gt; structure accepts a system specific
&lt;a href=&quot;https://golang.org/pkg/syscall/#SysProcAttr&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SysProcAttr&lt;/code&gt;&lt;/a&gt;
structure pointer, which has a
&lt;a href=&quot;https://golang.org/pkg/syscall/#Credential&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt;&lt;/a&gt; field used to
set the user and group ids of the child process. This is a no-op
operation, as by default the child process runs with the same user
and group ids of its parent.  But when we run it:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go run echo.go
fork/exec /bin/echo: operation not permitted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/golangpatch/what.jpeg&quot; alt=&quot;What?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait! Can’t we run a process with our own account??? This is non-sense.
Let’s investigate the root cause of this weird behavior. A system
call must be returning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPERM&lt;/code&gt; and causing the whole thing to collapse.
We can use &lt;a href=&quot;https://dtrace.org/blogs/about/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dtrace&lt;/code&gt;&lt;/a&gt; to discover
exactly what system call is failing:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;dtrace &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;syscall:::return/execname == &quot;echo&quot; &amp;amp;&amp;amp; arg0 &amp;lt; 0 &amp;amp;&amp;amp; errno == EPERM/{}&apos;&lt;/span&gt;
dtrace: description &lt;span class=&quot;s1&quot;&gt;&apos;syscall:::return&apos;&lt;/span&gt; matched 522 probes
CPU     ID                    FUNCTION:NAME
  0    338                 setgroups:return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above dtrace script logs all system calls executing in the context of our
process that return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPERM&lt;/code&gt; error. Explaining the details of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dtrace&lt;/code&gt; is beyond
the scope of this post, please refer to the &lt;a href=&quot;https://dtrace.org&quot;&gt;dtrace website&lt;/a&gt;
to find the documentation about it.&lt;/p&gt;

&lt;p&gt;The output shows that the &lt;a href=&quot;https://linux.die.net/man/2/setgroups&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;&lt;/a&gt;
system call is the guilty one.  If you look at the system call
&lt;a href=&quot;https://linux.die.net/man/2/setgroups&quot;&gt;manual page&lt;/a&gt; you see that it requires
admin privileges to succeed. But, why is Go runtime calling it? Below you
see the relevant piece of code inside Go
&lt;a href=&quot;https://golang.org/pkg/syscall/&quot;&gt;syscall package&lt;/a&gt; (as I am running a
macOS, this is the code specific for BSD kernels, Linux and Solaris
specific source codes are similar):&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// User and groups&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Credential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETGROUPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETGID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The reason is that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; struct has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups&lt;/code&gt; field representing an
array of supplementary group ids to pass to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;, and when
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential != nil&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; gets always called, even if didn’t set the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups&lt;/code&gt; property. And that’s where the problem lies,  you can’t set
process user and group id without issuing a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;. The solution
is to find a way to say “don’t bother with supplementary groups”.&lt;/p&gt;

&lt;h1 id=&quot;attempt-1-dont-call-setgroups-if-lengroups--0&quot;&gt;Attempt #1: don’t call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len(Groups) == 0&lt;/code&gt;&lt;/h1&gt;

&lt;p&gt;My first solution was the obvious one, don’t call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; if
the length of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups&lt;/code&gt; is zero. It works fine, except for one detail:
we now can’t clear the supplementary groups of the child process, which
is, above all, a security problem.&lt;/p&gt;

&lt;h1 id=&quot;attempt-2-dont-call-setgroups-if-groups--nil&quot;&gt;Attempt #2: don’t call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups == nil&lt;/code&gt;&lt;/h1&gt;

&lt;p&gt;After the security concern, my idea was to distinguish a empty group
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]uint32{}&lt;/code&gt;) from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; group. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups == nil&lt;/code&gt;, we skip
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;, otherwise we call it. This removes the previous issue,
but introduces another: it subtly breaks backward compatibility.
Previously, if you left &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups&lt;/code&gt; intact, the child process would
always try to clear supplementary groups, now it doesn’t.&lt;/p&gt;

&lt;h1 id=&quot;attempt-3-call-setgroups-only-if-groups-and-getgroups-mismatch&quot;&gt;Attempt #3: call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; only if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Groups&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getgroups&lt;/code&gt; mismatch&lt;/h1&gt;

&lt;p&gt;One of the code reviewers suggested to call
&lt;a href=&quot;https://linux.die.net/man/2/getgroups&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getgroups&lt;/code&gt;&lt;/a&gt; to get the
current set of supplementary groups and only call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt; if the
current and new groups set mismatch. Implementing this was trickier than
you might think. Here is a fairly straightforward implementation:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupsMismatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}{}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// User and groups&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Credential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupsize&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;groupsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_GETGROUPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cgroups&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;groupsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_GETGROUPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cgroups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupsMismatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cgroups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETGROUPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ngroups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETGID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Gid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RawSyscall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SYS_SETUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cred&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Uid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childerror&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a classic linear time array mismatch algorithm implemented
in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;groupsMismatch&lt;/code&gt; function. By definition, the array of groups are
unique, so we don’t have to worry about duplicated values. When the current
supplementary group set is different from the new one, we call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;
to apply the new group set. When we run it:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wcosta@Wanders-MBP:~ &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;work/golang/bin/go run test.go
fatal error: stack growth after fork

runtime stack:
runtime.throw&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x10d65ca, 0x17&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/panic.go:596 +0x95
runtime.newstack&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/stack.go:965 +0xcea
runtime.morestack&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/asm_amd64.s:398 +0x86

goroutine 1 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;running]:
runtime.makeslice&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x10b1940, 0xe, 0xe, 0x0, 0xe, 0x0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/slice.go:39 +0xf6 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc4200499d8 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc4200499d0
syscall.forkAndExecInChild&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc4200103d0, 0xc42000c380, 0x3, 0x3, 0xc420082000, 0x24, 0x24, 0x0, 0x0, 0xc420049cd8, ...&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/syscall/exec_bsd.go:171 +0x707 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049ad0 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc4200499d8
syscall.forkExec&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420010360, 0x9, 0xc42000c260, 0x2, 0x2, 0xc420049cd8, 0x20, 0xc42000c360, 0xc42001c000&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/syscall/exec_unix.go:193 +0x368 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049bf0 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049ad0
syscall.StartProcess&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420010360, 0x9, 0xc42000c260, 0x2, 0x2, 0xc420049cd8, 0x2, 0x4, 0xc420016180, 0xc420049ca8&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/syscall/exec_unix.go:240 +0x64 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049c48 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049bf0
os.startProcess&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420010360, 0x9, 0xc42000c260, 0x2, 0x2, 0xc420049e80, 0xc420012480, 0x23, 0x23&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/os/exec_posix.go:45 +0x1fb &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049d30 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049c48
os.StartProcess&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420010360, 0x9, 0xc42000c260, 0x2, 0x2, 0xc420049e80, 0x0, 0x0, 0xc42006e750&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/os/exec.go:94 +0x64 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049d88 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049d30
os/exec.&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;Cmd&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.Start&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420080000, 0xc42000c201, 0xc42000c300&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/os/exec/exec.go:359 +0x502 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049ed8 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049d88
os/exec.&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;Cmd&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.Run&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0xc420080000, 0xc42000c300, 0xc420049f68&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	/Users/wcosta/work/golang/src/os/exec/exec.go:277 +0x2b &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049f00 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049ed8
main.main&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
	/Users/wcosta/test.go:36 +0x21d &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049f88 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049f00
runtime.main&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/proc.go:185 +0x20a &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049fe0 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049f88
runtime.goexit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/asm_amd64.s:2197 +0x1 &lt;span class=&quot;nv&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049fe8 &lt;span class=&quot;nv&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0xc420049fe0

goroutine 17 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;syscall, locked to thread]:
runtime.goexit&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
	/Users/wcosta/work/golang/src/runtime/asm_amd64.s:2197 +0x1
&lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;status 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/golangpatch/saywhat.jpeg&quot; alt=&quot;Say What?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Before diving into the error, let’s talk a bit about the history of the
&lt;a href=&quot;https://linux.die.net/man/2/fork&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt;&lt;/a&gt; system call. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt; was
created, there was no concept of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Thread_\(computing\)&quot;&gt;threads&lt;/a&gt;,
forking the process was the way multiprocessing was achieved. As you probably
know, when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt; is called, a child process is spawned which is identical to
the parent process, like memory values and files opened. But what if a
multithreaded process calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt;? The answer is that only the thread that
invoked the system call is copied to the child process, but the state of the global
memory remains the same, and that includes the state of mutexes and semaphores
held in another thread. That means you can execute a very restrict set of
operations in the child process. Allocating memory from the heap is dangerous,
as the heap is often protected by a mutex, and another thread could be in the
middle of a heap allocation when the process was forked. Trying to allocate
memory from the heap in this circumstance will deadlock the child process.&lt;/p&gt;

&lt;p&gt;Another thing you need to know is that the goroutine stack is resizable, and
they are quite small when goroutines are created. If you are interested in
the details of goroutines stack management, I recommend this
&lt;a href=&quot;https://blog.cloudflare.com/how-stacks-are-handled-in-go/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok, with this background I can now explain what happened. The stack
trace points to the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroups := make([]uint32, groupsize)&lt;/code&gt;,
which tries to allocate a new array in the stack, the stack limit
is reached and then the go runtime tries to allocate more memory
to the stack, and the go runtime
&lt;a href=&quot;https://github.com/golang/go/blob/master/src/runtime/stack.go#L932-L934&quot;&gt;detects it is a forked process&lt;/a&gt;
and panics. The conclusion is that even a function call may cause
a runtime panic.&lt;/p&gt;

&lt;p&gt;In the end, to implement this patch I had to declare a global
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]uint32&lt;/code&gt; large enough to store the groups returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getgroups&lt;/code&gt;
(in environments I looked at, it doesn’t need to be more than 16
entries large) and implemented an \(O(n^2)\) but constant
space matching algorithm.&lt;/p&gt;

&lt;p&gt;It turns out it actually didn’t reach its goal, because often a new
child process inherits the parent’s supplementary groups. Therefore, even
so the caller doesn’t care about supplementary groups, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setgroups&lt;/code&gt;
can be called anyway.&lt;/p&gt;

&lt;h1 id=&quot;accepted-solution-define-a-new-member-in-the-credential-struct&quot;&gt;Accepted solution: define a new member in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; struct&lt;/h1&gt;

&lt;p&gt;After all previous attempts, I admitted defeat and added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoSetGroups&lt;/code&gt;
member to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Credential&lt;/code&gt; struct so that when it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;,
it skips supplementary groups management.
In a ideal world it would be called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetGroups&lt;/code&gt; with the logic inverted,
but I had to do so in order to preserve backward compatibility.&lt;/p&gt;

&lt;p&gt;If you are curious about the final patch, just look at the
&lt;a href=&quot;https://github.com/golang/go/commit/79f6a5c7bd684f2e6007ee505b522440beb86bf0&quot;&gt;git commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By the end of the day, it is just astonishing how a subtle issue with
a so simple patch yielded so much trouble. Finding the
perfect solution is often almost impossible, but even finding a good
one isn’t that simple.&lt;/p&gt;
</description>
        <pubDate>Sat, 11 Mar 2017 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/golang-patch/</link>
        <guid isPermaLink="true">https://walac.github.io/golang-patch/</guid>
        
        <category>go</category>
        
        
        <category>go</category>
        
      </item>
    
      <item>
        <title>Yet another &quot;Java faster than C++&quot; claim</title>
        <description>&lt;p&gt;Some days ago, a friend emailed me desperated because a Java code
was faster than his C++ implementation. These &lt;em&gt;Java faster than C++&lt;/em&gt; claims
were very common when Java was the tech companies fashion language. I never
liked Java because I always thought it was quite verbose (however, I never tried
the new functional constructions in Java 8) and used to be very heavy. I mean,
I could recognize that an app was written in Java in a blink of eyes, just by looking
how slow it was. Things have changed since, but as I was never a professional
Java programmer, I didn’t follow the language evolution.&lt;/p&gt;

&lt;p&gt;Back to the post, the code in question is a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Huffman_coding&quot;&gt;Huffman code&lt;/a&gt; implementation. He based his
&lt;a href=&quot;https://github.com/Spagiari/Stream-Data-Compactor/blob/master/src/Huffman.h&quot;&gt;C++ implementation&lt;/a&gt;
on &lt;a href=&quot;https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Huffman.java.html&quot;&gt;Sedgewick’s Java version&lt;/a&gt;.
If you want to profile on your own, you can clone his repo (as he already merged
my patches, you’ll need to rewind git history a bit to profile the old code). You can find instructions
on how install the Java code &lt;a href=&quot;https://algs4.cs.princeton.edu/code/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s get it started by using the simple &lt;a href=&quot;https://man7.org/linux/man-pages/man1/time.1.html&quot;&gt;time&lt;/a&gt; command.
In this test, we are measuring the time to compress and decompress
the sample &lt;a href=&quot;https://github.com/Spagiari/Stream-Data-Compactor/blob/master/test/mobydick.txt&quot;&gt;mobydick.txt&lt;/a&gt;
file. First let’s profile the compression and decompression times for the Java version:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;java edu.princeton.cs.algs4.Huffman - &amp;lt; mobydick.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; modydick.dwc

real  0m0.223s
user  0m0.255s
sys 0m0.034s

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;java edu.princeton.cs.algs4.Huffman + &amp;lt; mobydick.dwc &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mobydick.txt

real  0m0.186s
user  0m0.196s
sys 0m0.035s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, the C++ implementation:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./Huffman &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &amp;lt; mobydick.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mobydick.dwc

real  0m0.380s
user  0m0.364s
sys 0m0.009s

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./Huffman &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &amp;lt; mobydick.dwc &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mobydick.txt

real  0m0.352s
user  0m0.330s
sys 0m0.010s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Just for the record, I profiled the second execution of each command to make sure
results won’t differ because of file caching.&lt;/p&gt;

&lt;p&gt;Ok, C++ implementation is indeed slower, the question is why? After a rough look at
the source code, the heap allocations were quite suspicious, but after some
experiments I realized this was not the case, then I started to profile the code.
If you know me, you also know I am a very keen Linux user, but I had to switch to
Mac OS X for a &lt;a href=&quot;https://walac.github.io/taskcluster-worker-macosx-engine/&quot;&gt;project&lt;/a&gt; I am working
on at Mozilla. As I have no much experience on Mac development, and that includes
native tools, I made some google research and came across
&lt;a href=&quot;https://developer.apple.com/library/watchos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/index.html&quot;&gt;Instruments&lt;/a&gt;.
After some painful time trying to use it inside &lt;a href=&quot;https://www.wnd.com/files/2015/03/poop-emoji-emoticon-600-300x300.jpg&quot;&gt;Xcode&lt;/a&gt;,
I came back to google and found
&lt;a href=&quot;https://developer.apple.com/library/ios/recipes/Instruments_help_articles/Articles/CollectingandViewingDatawiththeiprofilerCommand-lineTool.html&quot;&gt;iprofiler&lt;/a&gt;.
That was a life saver, I could profile from command line and see the results on
Instruments GUI. Instruments come with a set of &lt;em&gt;Profiler templates&lt;/em&gt;, the one
of interest here is the &lt;em&gt;time profiler&lt;/em&gt;, which as its name says,
profiles the time spent on function calls. Let’s start by profiling the compression
operation:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;iprofiler &lt;span class=&quot;nt&quot;&gt;-timeprofiler&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; 100us bin/Huffman &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &amp;lt; mobydick.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mobydick.bwc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And now let’s look at the results:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cppjava/compressionProfile.png&quot; alt=&quot;Compression Profile&quot; style=&quot;width: 100%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The program spends most of the time reading the input file. Why that? Here is a simplified
version of the code that reads the input file:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;istream_iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;istream_iterator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The problem lies on using &lt;a href=&quot;https://www.cplusplus.com/reference/iostream/cin/&quot;&gt;std::cin&lt;/a&gt;
to read the file. ISO C++11 says that standard streams objects must be thread safe,
that means a mutex lock/unlock operation is executed each time the internal I/O buffer
is accessed. In the code above, a mutex is locked for each character read,
which makes things painfully slow. The solution is to use a
&lt;a href=&quot;https://www.cplusplus.com/reference/fstream/fstream/&quot;&gt;std::fstream&lt;/a&gt; object, as it has
no imposed lock contention. Obviously, all this applies to file writing as well, and
we take the same path of replacing &lt;a href=&quot;https://en.cppreference.com/w/cpp/io/cout&quot;&gt;std::cout&lt;/a&gt;
by &lt;a href=&quot;https://www.cplusplus.com/reference/fstream/fstream/&quot;&gt;std::fstream&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now let’s see how much we improved compression and decompression performance:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;bin/Huffman &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &amp;lt; mobydick.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mobydick.bwc

real  0m0.108s
user  0m0.095s
sys 0m0.007s

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;bin/Huffman &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; mobydick.txt &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; mobydick.bwc

real 0m0.215s
user 0m0.201s
sys  0m0.007s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;250% faster for compression and 63% for decompression!!!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cppjava/notbad.jpg&quot; alt=&quot;Not Bad&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Can we make this better? Hrm, lets profile it one more time, but this time,
we will profile decompression, since it is still slower than its Java
counterpart:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cppjava/decompressionProfile.png&quot; alt=&quot;Decompression Profile&quot; style=&quot;width: 100%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wait! What are those &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__shared_weak_count::__release_shared&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__add_shared&lt;/code&gt; calls consuming
almost half of the running time? If we take a look at the
&lt;a href=&quot;https://github.com/Spagiari/Stream-Data-Compactor/blob/c5a98eec543b77ced6d299f462382ecd64d07b48/src/Huffman.h&quot;&gt;implementation&lt;/a&gt;,
we see it uses &lt;a href=&quot;https://en.cppreference.com/w/cpp/memory/shared_ptr&quot;&gt;std::shared_ptr&lt;/a&gt; to allocate
the nodes for the Huffman tree. As you might know, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared_ptr&lt;/code&gt; provides a
smart pointer with a thread safe, reference counted, copy semantics. The code is single
threaded, so this thread safe reference counting is a waste of resources, but the point
is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shared_ptr&lt;/code&gt; is thread safe, and not going to suggest to implement a single
thread version of it. What do we do? Well, a careful review on the code shows that we
actually don’t need a smart pointer with copy semantics, the pointer is never shared,
but transferred from one owner to another, so what we need is
&lt;a href=&quot;https://tinyurl.com/d74bmox&quot;&gt;moving semantics&lt;/a&gt;, and we have a perfect smart pointer
with this characteristic:
&lt;a href=&quot;https://en.cppreference.com/w/cpp/memory/unique_ptr&quot;&gt;std::unique_ptr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By replacing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::shared_ptr&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;, we are free
from the reference counting contention. Let’s see how fast we got
with this change:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;bin/Huffman &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; mobydick.txt &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; mobydick.bwc

real  0m0.107s
user  0m0.092s
sys 0m0.008s

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;bin/Huffman &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; mobydick.txt &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; mobydick.bwc

real  0m0.120s
user  0m0.109s
sys 0m0.007s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wow! Decompression now, compared to the original code, is 193% faster!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cppjava/motherofgod.jpg&quot; alt=&quot;Mother of God&quot; /&gt;&lt;/p&gt;

&lt;p&gt;C++ code got a lot faster, and we achieved this with only intelligent use of the
standard C++ library, no need to implement lock free data structures, or fancy
algorithms or either special processor features. Sometimes, less is more.
If you want to take a look at the actual source code, you can visit
&lt;a href=&quot;https://github.com/Spagiari/Stream-Data-Compactor/pull/4&quot;&gt;my pull request&lt;/a&gt; (there is
an extra commit reversing a flawed attempt to optimizes the code preserving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::cin&lt;/code&gt;).
If I was asked to try to make the code even faster, I would give
&lt;a href=&quot;https://en.wikipedia.org/wiki/Memory-mapped_file&quot;&gt;file mapping&lt;/a&gt; a try, since
file I/O seems to be the bottleneck here. Maybe I do that in the future, and publish the
results here.&lt;/p&gt;

</description>
        <pubDate>Tue, 23 Aug 2016 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/java-faster-than-cpp/</link>
        <guid isPermaLink="true">https://walac.github.io/java-faster-than-cpp/</guid>
        
        <category>cpp</category>
        
        
        <category>cpp</category>
        
      </item>
    
      <item>
        <title>The taskcluster-worker Mac OSX engine</title>
        <description>&lt;p&gt;In this quarter, I worked on implementing the
&lt;a href=&quot;https://blog.gregarndt.com/taskcluster/2016/03/24/birth-of-new-worker/&quot;&gt;taskcluster-worker&lt;/a&gt;
Mac OSX engine. Before talking about this specific implementation,
let me explain what a worker is and how taskcluster-worker differs from
&lt;a href=&quot;https://github.com/taskcluster/docker-worker&quot;&gt;docker-worker&lt;/a&gt;, the currently
main worker in
&lt;a href=&quot;https://yourdomain.com/mozilla,%20ci/2014/03/04/taskcluster.html&quot;&gt;Taskcluster&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-role-of-a-taskcluster-worker&quot;&gt;The role of a Taskcluster worker&lt;/h1&gt;

&lt;p&gt;When a user submits a task graph to Taskcluster,
contrary to the common sense (at least if you are used on how OSes
schedulers usually work), these tasks are submitted to the scheduler first,
which is responsible to process dependencies and enqueue them. In the
&lt;a href=&quot;https://docs.taskcluster.net/manual&quot;&gt;Taskcluster manual page&lt;/a&gt; there is a
clear picture ilustrating this concept.&lt;/p&gt;

&lt;p&gt;The provisioner is responsible for looking at the queue and determine how
many pending tasks exist and, based on that, it launches worker instances to
run these tasks.&lt;/p&gt;

&lt;p&gt;Then comes the figure of the worker. The worker is responsible for actually
executing the task. It claims a task from the queue, runs it, upload the
generated artifacts and submits the status of the finished task, using the
&lt;a href=&quot;https://docs.taskcluster.net/manual/apis&quot;&gt;Taskcluster APIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-worker&lt;/code&gt; is a worker that runs task command inside a docker container.
The task payload specifies a &lt;a href=&quot;https://www.docker.com/what-docker&quot;&gt;docker&lt;/a&gt;
image as well as a command line to run, among other environment parameters.
docker-worker pulls the specified docker image and runs task commands inside it.&lt;/p&gt;

&lt;h1 id=&quot;taskcluster-worker-and-the-osx-engine&quot;&gt;taskcluster-worker and the OSX engine&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster-worker&lt;/code&gt; is a generic and modularized worker under active
development by the Taskcluster team. The worker delegates the task execution
to one of the available
&lt;a href=&quot;https://github.com/taskcluster/taskcluster-worker/tree/master/engines&quot;&gt;engines&lt;/a&gt;.
An engine is a component of taskcluster-worker responsible for running a task
under a specific system environment. Other features, like environment variable
setting, live logging, artifact uploading, etc., are handled by
&lt;a href=&quot;https://github.com/taskcluster/taskcluster-worker/tree/master/plugins&quot;&gt;worker plugins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am implementing the Mac OSX engine, which will mainly be used to run
Firefox automated tests in the Mac OSX environment. There is a
&lt;a href=&quot;https://github.com/walac/taskcluster-worker/tree/macosx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;macosx&lt;/code&gt; branch&lt;/a&gt; in
my personal Github taskcluster-worker fork in which I push my commits.&lt;/p&gt;

&lt;p&gt;One specific aspect of the engine implementation is the ability to run more
than one task at the same time. For this, we need to implement some kind
of task isolation. For docker-worker, each task ran in its own docker container
so tasks were isolated by definition. But there is no such thing as a container
for OSX engine. Our earlier tries with
&lt;a href=&quot;https://en.wikipedia.org/wiki/Chroot&quot;&gt;chroot&lt;/a&gt; failed miserably, due to
incompatibilities with OSX graphic system. Our final solution was to create a new user
on the fly and run the task with this user’s credentials. This not only provides
some task isolation, but also prevents privilege escalation attacks by running
tasks with different user than the worker.&lt;/p&gt;

&lt;p&gt;Instead of dealing with the poorly documented
&lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Networking/Conceptual/Open_Directory/Introduction/Introduction.html&quot;&gt;Open Directory Framework&lt;/a&gt;,
we chose to spawn the
&lt;a href=&quot;https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/dscl.1.html&quot;&gt;dscl&lt;/a&gt;
command to create and configure users. Tasks usually takes a long time to
execute, spawning loads of subprocess, so a few spawns of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dscl&lt;/code&gt; command
won’t have any practical performance impact.&lt;/p&gt;

&lt;p&gt;One final aspect is how we bootstrap task execution. A tasks boils down to
a script that executes task duties. But where does this script come from?
It doesn’t live in the machine that executes the worker. OSX engine provides a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;link&lt;/code&gt; field in task payload that a task can specify an executable to download and
execute.&lt;/p&gt;

&lt;h1 id=&quot;running-the-worker&quot;&gt;Running the worker&lt;/h1&gt;

&lt;p&gt;OSX engine will primarily be used to execute Firefox tests on Mac OSX,
and the environment is expected to have a very specific tools and
configurations set. Because of that, I am testing the code on a
&lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/How_To/Loan_a_Slave&quot;&gt;loaner machine&lt;/a&gt;.
To start the worker, it is just a matter of opening a terminal and typing:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./taskcluster-worker work macosx &lt;span class=&quot;nt&quot;&gt;--logging-level&lt;/span&gt; debug
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The worker connects to the Taskcluster queue, claims and execute the tasks available.
At the time I am writing, all tests but &lt;em&gt;Firefox UI functional&lt;/em&gt; tests” were green,
running on optimized Firefox OSX builds. We intend to land Firefox tests in taskcluster-worker as
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Supported_build_configurations&quot;&gt;Tier-2&lt;/a&gt; on next quarter,
running them in parallel with Buildbot.&lt;/p&gt;
</description>
        <pubDate>Mon, 27 Jun 2016 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/taskcluster-worker-macosx-engine/</link>
        <guid isPermaLink="true">https://walac.github.io/taskcluster-worker-macosx-engine/</guid>
        
        <category>taskcluster</category>
        
        
        <category>mozilla</category>
        
      </item>
    
      <item>
        <title>Overcoming browser same origin policy</title>
        <description>&lt;p&gt;One of my goals for 2016 Q1 was to write a
&lt;a href=&quot;https://tools.taskcluster.net/status/&quot;&gt;monitoring dashboard&lt;/a&gt; for Taskcluster.
It basically pings Taskcluster services to check if they are alive and also
acts as a feed aggregator for services Taskcluster depends on. One problem with
this approach is the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Same-origin_policy&quot;&gt;same origin policy&lt;/a&gt;, in which
web pages are only allowed to make requests to their own domain. For web servers
which is safe to make these cross domain requests, they can either implement
&lt;a href=&quot;https://en.wikipedia.org/wiki/JSONP&quot;&gt;jsonp&lt;/a&gt; or
&lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;CORS&lt;/a&gt;. CORS is the
preferred way so we will focus on it for this post.&lt;/p&gt;

&lt;h2 id=&quot;cross-origin-resource-sharing&quot;&gt;Cross-origin resource sharing&lt;/h2&gt;

&lt;p&gt;CORS is a mechanism that allows the web server tell the browser that is safe to
accomplish a cross domain request. It consists of a set of HTTP headers with details
for the conditions to accomplish the request. The main response header is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Allow-Origin&lt;/code&gt;, which contains either a list of allowed domains or
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;, indicating any domain can make a cross request to this server. In a CORS
request, only a small set of headers is exposed to the response object. The server
can tell the browser to expose additional headers through the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Access-Control-Expose-Headers&lt;/code&gt; response header.&lt;/p&gt;

&lt;p&gt;But what if the web server doesn’t implement CORS? The only solution is to provide
a proxy that will make the actual request and add the CORS headers.&lt;/p&gt;

&lt;h2 id=&quot;cors-proxy&quot;&gt;cors-proxy&lt;/h2&gt;

&lt;p&gt;To allow the monitoring dashboard make requests for status state on remote services
that do not implement CORS, we created the
&lt;a href=&quot;https://github.com/taskcluster/cors-proxy&quot;&gt;cors-proxy&lt;/a&gt;. It exports a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/request&lt;/code&gt;
endpoint that allows you to make requests to any remote host. cors-proxy redirects
it to the remote URL and sends the responses back, with appropriate CORS headers set.&lt;/p&gt;

&lt;p&gt;Let’s see an example:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://cors-proxy.taskcluster.net/request&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://queue.taskcluster.net/v1/ping&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The information about the remote request is sent in the proxy request body. All
parameter fields are shown in the project page.&lt;/p&gt;

&lt;p&gt;Before you think on using the hosted server to bypass your own requests, cors-proxy
only honors requests from a
&lt;a href=&quot;https://github.com/taskcluster/cors-proxy/blob/master/server.js#L12-L15&quot;&gt;whitelist&lt;/a&gt;.
So, only some subdomains under Taskcluster domain can use cors-proxy.&lt;/p&gt;

</description>
        <pubDate>Fri, 01 Apr 2016 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/cors-proxy/</link>
        <guid isPermaLink="true">https://walac.github.io/cors-proxy/</guid>
        
        <category>taskcluster</category>
        
        
        <category>taskcluster</category>
        
      </item>
    
      <item>
        <title>In tree tasks configuration</title>
        <description>&lt;p&gt;This post is about our plans for representing Taskcluster tasks inside
the gecko tree. &lt;a href=&quot;https://jonasfj.dk/&quot;&gt;Jonas&lt;/a&gt;,
&lt;a href=&quot;https://code.v.igoro.us/&quot;&gt;Dustin&lt;/a&gt; and I had a discussion in Berlin about this,
here I summarize what we have so far. We currently store tasks in an
&lt;a href=&quot;https://yaml.org/&quot;&gt;yaml&lt;/a&gt; file and they translate to json format using the
mach command. The syntax we have now is not the most flexible one, it is hard
to parameterize the task and very difficulty to represents tasks relationships.&lt;/p&gt;

&lt;p&gt;Let us illustrate the shortcomings with two problems we currently have.
Both apply to B2G.&lt;/p&gt;

&lt;p&gt;B2G (as in Android) has three different
&lt;a href=&quot;https://source.android.com/source/building.html#choose-a-target&quot;&gt;build variants&lt;/a&gt;:
user, userdebug and eng. Each one has slightly different task configurations.
As there is no flexible way to parameterize tasks, we end up with one different
task file for each build variant.&lt;/p&gt;

&lt;p&gt;When doing nightly builds, we must send update data to the OTA server.
We have plans to run a build task, then run the test tasks on this build,
and if all tests pass, we run a task responsible to update the OTA server.
The point is that today we have no way to represent this relationship
inside the task files.&lt;/p&gt;

&lt;p&gt;For the first problem Jonas has a prototype for
&lt;a href=&quot;https://github.com/jonasfj/json-parameterization&quot;&gt;json parameterization&lt;/a&gt;. There
were discussions on Berlin work week either we should stick with yaml files
or use Python files for task configuration. We do want to keep the syntax
declarative, which favors yaml, but storing configurations in Python files
brings much more expressiveness and flexibility, but this can result in
the same configuration hell we have with Buildbot.&lt;/p&gt;

&lt;p&gt;The second problem is more complex, and we still haven’t reached a final design.
The first question is how we describe task dependencies, top-down, i.e., we
specify which task(s) should run after a completed task, or ground up, a task
specifies which tasks it depends on. In general, we all agreed to go to a
top-down syntax, since most scenarios beg for a top down approach. Other
either should put the description of tasks relationship inside the task
files or in a separated configuration file. We would like to represent task
dependencies inside the task file, the problem is how to check what’s the
root task for the task graph. One suggestion is having a task file called
root.yml which only contain root tasks.&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Oct 2015 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/in-tree-config/</link>
        <guid isPermaLink="true">https://walac.github.io/in-tree-config/</guid>
        
        <category>taskcluster</category>
        
        
        <category>taskcluster</category>
        
      </item>
    
      <item>
        <title>Running phone builds on Taskcluster</title>
        <description>&lt;p&gt;In this post I am going to talk about my work for phone builds inside the
&lt;a href=&quot;https://docs.taskcluster.net/&quot;&gt;Taskcluster&lt;/a&gt; infrastructure. Mozilla is
slightly moving from Buildbot to Taskcluster. Here I am going to
give a survivor guide on Firefox OS phone builds.&lt;/p&gt;

&lt;h2 id=&quot;submitting-tasks&quot;&gt;Submitting tasks&lt;/h2&gt;

&lt;p&gt;A task is nothing more than a json file containing the description 
of the job to execute. But you don’t need to handle the json directly, all tasks
are written in &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;, and it is then processed
by the &lt;a href=&quot;https://mzl.la/1MkZ4gz&quot;&gt;mach&lt;/a&gt; command. The in tree tasks are located
at &lt;a href=&quot;https://mzl.la/1MkYOhw&quot;&gt;testing/taskcluster/tasks&lt;/a&gt; and the build tasks are
inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builds/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;My favorite command to try out a task is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mach taskcluster-build&lt;/code&gt; command.
It allows you to process a single task and output the json formatted task ready
for Taskcluster submission.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./mach taskcluster-build &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--head-repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https://hg.mozilla.org/mozilla-central 
    &lt;span class=&quot;nt&quot;&gt;--head-rev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tip &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--owner&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;foobar@mozilla.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    tasks/builds/b2g_desktop_opt.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Although we specify a Mercurial repository, Taskcluster also accepts git
repositories interchangeably.&lt;/p&gt;

&lt;p&gt;This command will print out the task to the console output. To
run the task, you can copy the generated task and paste it in the
&lt;a href=&quot;https://tools.taskcluster.net/task-creator/&quot;&gt;task creator&lt;/a&gt; tool. Then just
click on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Create Task&lt;/code&gt; to schedule it to run. Remember that you need
&lt;a href=&quot;https://auth.taskcluster.net/&quot;&gt;Taskcluster Credentials&lt;/a&gt; to run Taskcluster
tasks. If you have
&lt;a href=&quot;https://www.npmjs.com/package/taskcluster-cli/&quot;&gt;taskcluster-cli&lt;/a&gt;
installed, you can the pipe the mach output to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;taskcluster run-task&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tasks are effectively executed inside a &lt;a href=&quot;https://www.docker.com/&quot;&gt;docker&lt;/a&gt;
&lt;a href=&quot;https://dxr.mozilla.org/mozilla-central/source/testing/docker&quot;&gt;image&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;mozharness&quot;&gt;Mozharness&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/Mozharness&quot;&gt;Mozharness&lt;/a&gt;
is what we use for effectively build stuff. Mozharness
architecture, despite its code size, is quite simple. Under the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt; directory you find the harness scripts. We are specifically
interested in the &lt;a href=&quot;https://tinyurl.com/nlm8mjm&quot;&gt;b2g_build.py&lt;/a&gt; script. As the script
name says, it is responsible for B2G builds. The B2G harness configuration
files are located at the &lt;a href=&quot;https://tinyurl.com/nzqlkfe&quot;&gt;b2g/config&lt;/a&gt; directory. Not
surprisingly, all files starting with “taskcluster” are for Taskcluster
related builds.&lt;/p&gt;

&lt;p&gt;Here are the most common configurations:&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;default_vcs&lt;/dt&gt;
  &lt;dd&gt;This is the default vcs used to clone repositories when no other is given.
  [tc_vcs](https://tc-vcs.readthedocs.org/en/latest/) allows mozharness to
  clone either git or mercurial repositories transparently, with repository
  caching support.&lt;/dd&gt;
  &lt;dt&gt;default_actions&lt;/dt&gt;
  &lt;dd&gt;The actions to execute. They must be present and in the same order as
  in the build class `all_actions` attribute.&lt;/dd&gt;
  &lt;dt&gt;balrog_credentials_file&lt;/dt&gt;
  &lt;dd&gt;The credentials to send update data to the OTA server.&lt;/dd&gt;
  &lt;dt&gt;nightly_build&lt;/dt&gt;
  &lt;dd&gt;`True` if this is a nightly build.&lt;/dd&gt;
  &lt;dt&gt;upload&lt;/dt&gt;
  &lt;dd&gt;Upload info. Not used for Taskcluster.&lt;/dd&gt;
  &lt;dt&gt;repo_remote_mappings&lt;/dt&gt;
  &lt;dd&gt;Maps externals repository to [mozilla domain](https://git.mozilla.org).&lt;/dd&gt;
  &lt;dt&gt;env&lt;/dt&gt;
  &lt;dd&gt;Environment variables for commands executed inside mozharness.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;The listed actions map to Python methods inside the build class, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; replaced
by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;. For example, the action &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout-sources&lt;/code&gt; maps to the method
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout_sources&lt;/code&gt;. That’s where the mozharness simplicity comes from: everything boils
down to a sequence of method calls, just it, no secret.&lt;/p&gt;

&lt;p&gt;For example, here is how you run mozharness to build a flame image:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python &amp;lt;gecko-dir&amp;gt;/testing/mozharness/scripts/b2g_build.py &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; b2g/taskcluster-phone.py &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--disable-mock&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--variant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;user &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--work-dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;B2G &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--gaia-languages-file&lt;/span&gt; locales/languages_all.json &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--log-level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;debug &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;flame-kk &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--b2g-config-dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;flame-kk &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--repo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https://hg.mozilla.org/mozilla-central &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Remember you need your flame connected to the machine so the build system
can extract the blobs.&lt;/p&gt;

&lt;p&gt;In general you don’t need to worry about mozharness command line because it is wrapped
by the &lt;a href=&quot;https://tinyurl.com/py798c3&quot;&gt;build scripts&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;hacking-taskcluster-b2g-builds&quot;&gt;Hacking Taskcluster B2G builds&lt;/h2&gt;

&lt;p&gt;All Taskcluster tasks run inside a docker container. Desktop and emulator B2G builds
run inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builder&lt;/code&gt; docker image. Phone builds are more complex, because:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Mozilla is not allowed to publicly redistribute phone binaries.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Phone build tasks need to access the &lt;a href=&quot;https://wiki.mozilla.org/Balrog&quot;&gt;Balrog&lt;/a&gt;
  server to send OTA update data.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Phone build tasks need to upload symbols to the
  &lt;a href=&quot;https://mzl.la/1Ta6jfY&quot;&gt;crash reporter&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Due to (1), only users authenticated with a @mozilla account are allowed
to download phone binaries (this works the same way as private builds). And
because of (1), (2) and (3), the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phone-builder&lt;/code&gt; docker image is secret,
so only authorized users can submit tasks to it.&lt;/p&gt;

&lt;p&gt;If you need to create a build task for a new phone, most of the time you will
starting from an existing task (Flame and Aries tasks are preferred) and then
make your customizations. You might need to add new features to the
&lt;a href=&quot;https://tinyurl.com/py798c3&quot;&gt;build scripts&lt;/a&gt;, which currently are not the most
flexible scripts around.&lt;/p&gt;

&lt;p&gt;If you need to customize mozharness, make sure your changes are Python 2.6
compatible, because mozharness is used to run Buildbot builds too, and the
Buildbot machines run Python 2.6. The best way to minimize risk of breaking
stuff is to submit your patches to try with “-p all -b do” flags.&lt;/p&gt;

&lt;p&gt;Need help? Ask at the #taskcluster channel.&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Oct 2015 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/taskcluster-b2g/</link>
        <guid isPermaLink="true">https://walac.github.io/taskcluster-b2g/</guid>
        
        <category>taskcluster</category>
        
        
        <category>mozilla</category>
        
      </item>
    
      <item>
        <title>Mercurial for git lovers</title>
        <description>&lt;p&gt;So far I have been a heavy &lt;a href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt; user, but since I joined
&lt;a href=&quot;https://www.mozilla.org&quot;&gt;Mozilla&lt;/a&gt; I have given
&lt;a href=&quot;https://mercurial.selenic.com/&quot;&gt;Mercurial&lt;/a&gt; a try. I must
say that migrating from &lt;a href=&quot;https://subversion.apache.org/&quot;&gt;Subversion&lt;/a&gt; to git
was far less painful than from git to Mercurial. I think there are a few
reasons for that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;When I started to learn git, I started it with
&lt;a href=&quot;https://walac.github.io/pyusb&quot;&gt;PyUSB&lt;/a&gt;, a small personal project that was on its
youth at that time. This means I needed just the most basic commands to start
using it. When I started on Mercurial, I was working on
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Gecko&quot;&gt;Gecko&lt;/a&gt;, a very big and
complex project, with thousands of contributors, so I had to learn
more advanced commands from day one.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;When you install git, you have all you need, all commands you need are there.
Mercurial, in the other hand,
&lt;a href=&quot;https://gregoryszorc.com/blog/2013/05/12/thoughts-on-mercurial-%28and-git%29/&quot;&gt;operates in a very different way&lt;/a&gt;.
It just ships with some basic commands, delegating most of the more advanced
stuff to extensions. So you have to dig to find the extensions that enable the
Mercurial approach to commands you love in git.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There is nothing like git branches parallel in Mercurial, and 9/10 of git users’
workflow rely heavily on branches (more on that later).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the day to day commands in Mercurial are quite similar to git, like
&lt;a href=&quot;https://selenic.com/hg/help/clone&quot;&gt;clone&lt;/a&gt; and
&lt;a href=&quot;https://selenic.com/hg/help/commit&quot;&gt;commit&lt;/a&gt;. Some others have very different names,
like &lt;a href=&quot;https://git-scm.com/docs/git-revert&quot;&gt;git revert&lt;/a&gt;, which in Mercurial
is called &lt;a href=&quot;https://mercurial.selenic.com/wiki/Backout&quot;&gt;backout&lt;/a&gt;.
&lt;a href=&quot;https://selenic.com/hg/help/revert&quot;&gt;hg revert&lt;/a&gt; is used to discard non-committed
changes in your repository.&lt;/p&gt;

&lt;p&gt;I prepared a list of some Mercurial extensions that will make your life easier
when coming from git. These extensions will make you feel more comfortable
while moving from git to Mercurial.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;div&gt;&lt;table border=1 cellpadding=3&gt;
    &lt;tr&gt;
        &lt;th&gt;git feature&lt;/th&gt;
        &lt;th&gt;Mercurial extension&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#Colors-in-Git&quot;&gt;color&lt;/a&gt;          &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/ColorExtension&quot;&gt;Color&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-rebase&quot;&gt;git rebase&lt;/a&gt;                                                &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/RebaseExtension&quot;&gt;Rebase&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase-i&quot;&gt;Interactive rebase&lt;/a&gt;    &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/HisteditExtension&quot;&gt;Histedit&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-stash&quot;&gt;git stash&lt;/a&gt;                                                  &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/ShelveExtension&quot;&gt;Shelve&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-clean&quot;&gt;git clean&lt;/a&gt;                                                  &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/PurgeExtension&quot;&gt;Purge&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.kernel.org/pub/software/scm/git/docs/git-add.html&quot;&gt;git add -i&lt;/a&gt;                     &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/RecordExtension&quot;&gt;Record&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/gitk&quot;&gt;gitk&lt;/a&gt;                                                            &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/HgkExtension&quot;&gt;Hgk&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://fedoraproject.org/wiki/Git_quick_reference#Display_current_branch_in_bash&quot;&gt;__git_ps1&lt;/a&gt; &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/PromptExtension&quot;&gt;Prompt&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-cherry-pick&quot;&gt;git cherry-pick&lt;/a&gt;                                      &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/TransplantExtension&quot;&gt;Transplant&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-send-email&quot;&gt;git send-email&lt;/a&gt;                                        &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/PatchbombExtension&quot;&gt;PatchBomb&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-am&quot;&gt;git am&lt;/a&gt;                                                        &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/MboxExtension&quot;&gt;Mbox&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://fiji.sc/Git_topic_branches&quot;&gt;Topic branches&lt;/a&gt;                                             &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/BookmarksExtension&quot;&gt;Bookmarks&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://git-scm.com/docs/git-log&quot;&gt;Paged log&lt;/a&gt;                                                    &lt;/td&gt;
        &lt;td&gt; &lt;a href=&quot;https://mercurial.selenic.com/wiki/PagerExtension&quot;&gt;Pager&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This &lt;a href=&quot;https://mercurial.selenic.com/wiki/GitConcepts&quot;&gt;link&lt;/a&gt; has a lot more
information about differences between git and Mercurial, including Mercurial
counterparts for several git actions.&lt;/p&gt;

&lt;p&gt;Mercurial comes with an important feature that there is no equivalent
in git at all, called &lt;a href=&quot;https://mercurial.selenic.com/wiki/Phases&quot;&gt;phases&lt;/a&gt;.
I mention it here because you may have problems with it if you (like me)
do a lot of rebase and history editing. Every commit you push or pull
to/from a remote repository is considered &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt;, which makes it
immutable. This happens all the time to me because I often push commits to
&lt;a href=&quot;https://wiki.mozilla.org/ReleaseEngineering/TryServer&quot;&gt;Mozilla Try&lt;/a&gt;
and &lt;a href=&quot;https://reviewboard.mozilla.org&quot;&gt;reviewboard&lt;/a&gt;. Thus, I generally
face errors like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    hg rebase -d bookmark0
    abort: can&apos;t rebase immutable changeset 35c25b97fca2
    (see hg help phases for details)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s because I have pushed this commit and Mercurial made it
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; (aka immutable). The solution for this is make it
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; commit again:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    hg phase --draft --force bookmark3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I find this feature very annoying and I think it would be better
implemented as an extension. It sounds Java telling me what I
can and can’t do. You can disable making commits public after
a push by adding these entries in your
&lt;a href=&quot;https://www.selenic.com/mercurial/hgrc.5.html&quot;&gt;hgrc&lt;/a&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [phases]
    publish = False
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;special-note-on-bookmarks&quot;&gt;Special note on Bookmarks&lt;/h3&gt;

&lt;p&gt;Since Mercurial version 1.8, Bookmarks are now part of Mercurial core. They are
often advertised as &lt;em&gt;git branches on Mercurial&lt;/em&gt;. &lt;strong&gt;They are not&lt;/strong&gt;! The most
difficult part for me was to understand that Mercurial has no branch
support like git. Period. Bookmarks are just a hack that tries
to mimic topic branches, but, technically, a bookmark is not a branch, it is
more like a tag. I am not going to explain how Bookmarks work, you can learn more
on it &lt;a href=&quot;https://mercurial.aragost.com/kick-start/en/bookmarks/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most irritating thing regarding Bookmarks is that changing the history in
one bookmark can affect other bookmarks as well. In some cases, when you
create multiple heads descending from a bookmark, you cannot edit its
history at all. Let’s try an example. Imagine you fix a bug and submit it
for review. While you wait for feedback, you create more bookmarks to work
on other product features. You eventually end up with a tree like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    @ bookmark 3
    |
    | o bookmark 2
    |/
    |
    | o bookmark 1
    |/
    |
    o bookmark 0 (bug 137463)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; indicates the commit representing the current directory.&lt;/p&gt;

&lt;p&gt;After a while you receive feedback for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bug 137463&lt;/code&gt; and you are requested
some changes. You then move back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark 0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    o bookmark 3
    |
    | o bookmark 2
    |/
    |
    | o bookmark 1
    |/
    |
    @ bookmark 0 (bug 137463)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And start to apply the requested changes, making a new commit:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    o bookmark 3
    |
    | o bookmark 2
    |/
    |
    | o bookmark 1
    |/
    |
    | @ bookmark 0 (bug 137463)
    |/
    |
    o commit 1 (original bug 137453 commit)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark 0&lt;/code&gt; moved to the new commit.
What you want now is to squash &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit 1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark 0&lt;/code&gt;, but you can’t,
because you will mess up bookmarks 1-3. One solution would be to rebase
bookmarks 1-3 on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark 0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    o bookmark 3
    |
    | o bookmark 2
    |/
    |
    | o bookmark 1
    |/
    |
    @ bookmark 0 (bug 137463)
    |
    o commit 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;histedit&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit 1&lt;/code&gt; and squash it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bookmark 0&lt;/code&gt;, right?
Wrong! This happens because the structure you see is just an illusion from
branching point of view. In git, when you modify a branch, it doesn’t affect
descendant branches. In Mercurial this is not true simply because all the commits
&lt;strong&gt;are in the same branch&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;If your git workflow relies heavily on git branching capabilities and history
editing, you will have some trouble to adapt yourself to Mercurial (like me).&lt;/p&gt;

&lt;p&gt;If I could request just one feature to Mercurial developers, that would be
lightweight branches like git. That would give Mercurial a big boost.&lt;/p&gt;

&lt;p&gt;There are other problems I had with bookmarks regarding remote repositories,
but I will save that for a future post.&lt;/p&gt;
</description>
        <pubDate>Sat, 03 Jan 2015 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/mercurial-for-git-lovers/</link>
        <guid isPermaLink="true">https://walac.github.io/mercurial-for-git-lovers/</guid>
        
        <category>mercurial</category>
        
        
        <category>VCS</category>
        
      </item>
    
      <item>
        <title>Profiling Firefox OS apps</title>
        <description>&lt;p&gt;B2G has a &lt;a href=&quot;https://tinyurl.com/B2Gprofile&quot;&gt;built-in profiler&lt;/a&gt; that you can use to
find hot spots in your app.  The process is made easy by the
&lt;a href=&quot;https://tinyurl.com/profilesh&quot;&gt;profile.sh&lt;/a&gt; script, which helps you to generate
a profile file for upload to the
&lt;a href=&quot;https://people.mozilla.org/~bgirard/cleopatra/&quot;&gt;Cleopatra&lt;/a&gt; application.&lt;/p&gt;

&lt;p&gt;Earlier, you had to build your own Firefox OS image to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh&lt;/code&gt;
tool, but that’s no longer the case. Thanks to
&lt;a href=&quot;https://github.com/vdjeric/Snappy-Symbolication-Server&quot;&gt;Snappy symbolication server&lt;/a&gt;,
you can grab a &lt;a href=&quot;https://ftp.mozilla.org/pub/mozilla.org/b2g/nightly/&quot;&gt;Mozilla nightly&lt;/a&gt;
image and start to investigate where your app is wasting time.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh&lt;/code&gt; communicates with the device through
&lt;a href=&quot;https://developer.android.com/tools/help/adb.html&quot;&gt;adb&lt;/a&gt;, so you need to enable
it in the &lt;a href=&quot;https://tinyurl.com/fxosdevmenu&quot;&gt;developer menu&lt;/a&gt;. You also need an
engineering build image of your device (images with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-eng&lt;/code&gt; suffix).&lt;/p&gt;

&lt;p&gt;In this post, I am going into the steps to get a profile stack trace for your app.
In a few words, you have to follow a some steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Start the b2g process and your application with profile support.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perform the actions you want to profile.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Capture the profiles from the device.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Upload profile to
&lt;a href=&quot;https://people.mozilla.org/~bgirard/cleopatra/&quot;&gt;Cleopatra&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;starting-with-profile-support&quot;&gt;Starting with profile support&lt;/h2&gt;

&lt;p&gt;In general, you want to start profile support in the B2G parent process’ compositor
thread and your app. The template for this procedure is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./profile.sh start -p b2g -t Compositor &amp;amp;&amp;amp; ./profile.sh start -p &amp;lt;your-app&amp;gt;&lt;/code&gt;.
If you don’t know the app name, you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh ps&lt;/code&gt; command to
list the B2G processes:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./profile.sh ps
  PID Name
&lt;span class=&quot;nt&quot;&gt;-----&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;----------------&lt;/span&gt;
  208 b2g              profiler not running
  399 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Nuwa&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;           profiler not running
  896 Built-in Keyboa  profiler not running
 1059 Homescreen       profiler not running
 1251 Usage            profiler not running
 2238 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Preallocated a  profiler not running
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For this example, we are going to start profile for Homescreen application:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./profile.sh start &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; b2g &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; Compositor &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./profile.sh start &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; Homescreen
Process: b2g
Threads: Compositor
Using default features js,leaf,threads
Starting profiling PID 208..
Profiler started

Process: Homescreen
Using default features js,leaf
Starting profiling PID 1059..
Profiler started
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should now take your phone and perform the actions you would like to profile.&lt;/p&gt;

&lt;h2 id=&quot;getting-profile-files&quot;&gt;Getting profile files&lt;/h2&gt;

&lt;p&gt;Pulling profile data from the devices is performed by running
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh capture&lt;/code&gt; command. One of the steps performed
is symbol resolution. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile capture&lt;/code&gt; provides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt;
option which allows you to pass the URL of the
&lt;a href=&quot;https://github.com/vdjeric/Snappy-Symbolication-Server&quot;&gt;symbolication server&lt;/a&gt;,
that perform symbol resolution.&lt;/p&gt;

&lt;p&gt;For Firefox OS oficial builds, you can use the
&lt;a href=&quot;https://symbolapi.mozilla.org&quot;&gt;Mozilla symbolication server&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./profile.sh capture &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; https://symbolapi.mozilla.org
Symbols: https://symbolapi.mozilla.org
Signaling Profiled Processes: 208 1059
Stabilizing 208 b2g ...
Pulling /data/local/tmp/profile_0_208.txt into profile_208_b2g.txt
Adding symbols to profile_208_b2g.txt and creating profile_208_b2g.sym ...
Stabilizing 1059 Homescreen ...
Pulling /data/local/tmp/profile_2_1059.txt into profile_1059_Homescreen.txt
Adding symbols to profile_1059_Homescreen.txt and creating profile_1059_Homescreen.sym ...
Merging profile:  profile_208_b2g.sym profile_1059_Homescreen.sym
./gecko/tools/profiler/merge-profiles.py profile_208_b2g.sym profile_1059_Homescreen.sym

Results: profile_captured.sym
Removing old profile files &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;from device&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; ... &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The format of the pulled files is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile_PID_NAME.txt&lt;/code&gt; and the files with
symbols resolved have the same name but with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sym&lt;/code&gt; extension. It also
creates a merged file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile_captured.sym&lt;/code&gt;. After that, you can
&lt;a href=&quot;https://tinyurl.com/CleopatraUpload&quot;&gt;upload the results to Cleopatra&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cleopatra.jpg&quot; alt=&quot;cleopatra&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;symbol-resolution-through-breakpad-symbols&quot;&gt;Symbol resolution through breakpad symbols&lt;/h2&gt;

&lt;p&gt;That’s not the end of the story. Symbolication server makes use of the
&lt;a href=&quot;https://code.google.com/p/google-breakpad/&quot;&gt;google-breakpad&lt;/a&gt; symbol files
for symbol resolution. Firefox already uses breakpad for the crash reporting
system. When you build your own B2G image, you use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.sh&lt;/code&gt; script,
and it can also be used to generate breakpad symbols:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./build.sh buildsymbols
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The symbols will be generated in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GECKO_OBJDIR/dist/crashreporter-symbols&lt;/code&gt;
directory. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh&lt;/code&gt; also accepts the path to the breakpad
symbols directory for local symbol resolution, so you can also profile using
breakpad symbols:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./profile.sh capture &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GECKO_OBJDIR&lt;/span&gt;/dist/crashreporter-symbols/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile_captured.sym&lt;/code&gt; file will be generated as usual.&lt;/p&gt;

&lt;p&gt;If you distribute the breakpad symbols with your custom Firefox OS image anyone
can profile it.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This post was intented to be a brief tutorial on how to get profiles for your app
without building your own Firefox OS image. Currently, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile.sh&lt;/code&gt; is shipped
with private builds only, and it will
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1078369&quot;&gt;eventually ships with Nightly too&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any doubts, ping &lt;a href=&quot;https://mozillians.org/en-US/u/wcosta/&quot;&gt;me&lt;/a&gt;
on &lt;a href=&quot;https://www.standu.ps/project/fxos-automation&quot;&gt;#fxos-automation&lt;/a&gt; room.&lt;/p&gt;
</description>
        <pubDate>Thu, 16 Oct 2014 00:00:00 +0000</pubDate>
        <link>https://walac.github.io/profiling-firefox-os-apps/</link>
        <guid isPermaLink="true">https://walac.github.io/profiling-firefox-os-apps/</guid>
        
        <category>B2G</category>
        
        <category>performance</category>
        
        <category>profiling</category>
        
        <category>mozilla</category>
        
        
        <category>mozilla, B2G</category>
        
      </item>
    
  </channel>
</rss>
