This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: container_of - complex indirections - guru code - workqueues
- From: Josh Stone <jistone at redhat dot com>
- To: "Turgis, Frederic" <f-turgis at ti dot com>
- Cc: SystemTap <systemtap at sourceware dot org>
- Date: Thu, 29 Sep 2011 13:39:08 -0700
- Subject: Re: container_of - complex indirections - guru code - workqueues
- References: <13872098A06B02418CF379A158C0F14601638252E6@dnce02.ent.ti.com>
On 09/28/2011 04:17 PM, Turgis, Frederic wrote:
> I have assumed that guru code is only method to get data in following cases:
> 1 - data is retrieved by a "container_of(...)" syntax
If we ever get to PR11207 (preprocessor macros), this would be a good
one to add. In the meantime though, you can emulate it:
offsetof(type, member) = & @cast(0, "type")->member
container_of(ptr, type, member) = ptr - & @cast(0, "type")->member
> 2 - specific method like
> unsigned long data = atomic_long_read(&work->data);
> return (void *)(data & WORK_STRUCT_WQ_DATA_MASK);
> => then it would do (struct cpu_workqueue_struct *)data->wq->name
You can do most of this directly -- only getting the value of the MASK
is tricky. You could do it with a tiny embedded %{ MASK %} block
though, or else hard-code it.
> On top of that, I also have the issue that definitions are sometimes
> internal to C file like "struct cpu_workqueue_struct" so I mix guru code
> and @cast (summarized below):
> function get_workqueue_pointer:long(ref:long) %{
> struct work_struct *work; unsigned long data;
>
> work = (struct work_struct *)((uint32_t)(THIS->ref));
As an aside, (long) is a more portable intermediary for casting int64_t
arguments to pointers.
> data = atomic_long_read(&work->data);
> THIS->__retvalue = (data & WORK_STRUCT_WQ_DATA_MASK);
> %}
>
> probe kernel.function("process_one_work") {
> workqueue = get_workqueue_pointer($work);
> printf("process_one_work %p %s \n", $work->func, kernel_string(@cast(workqueue, "struct cpu_workqueue_struct")->wq->name));
> }
>
> Sounds reasonable or too hackish (shall I duplicate kernel code into my
> script) ? If you look at the code, you may find better solutions using
> same probe at a specific line of code but I wanted something more
> maintainable
How about:
probe kernel.function("process_one_work") {
workqueue = atomic_long_read(& $work->data)
workqueue &= %{ WORK_STRUCT_WQ_DATA_MASK %}
name = @cast(workqueue, "struct cpu_workqueue_struct")->wq->name
printf("process_one_work %p %s \n",
$work->func, kernel_string(name));
}
That will still require a little guru to get the mask, but hopefully you
find that nicer.
> For curious people, I am doing this because of June patch on
> workqueues: it gathered associated kernel threads into a common pool
> so there is no direct association between kernel thread and workqueue
> name. You only get "kworker/x:y" or "kworker/u:y" task name :-(
> Worse, 1 execution of a kworker task can correspond to consecutive
> executions of several workqueues. So I needed to track
> "process_one_work(...)" execution with pointer on function executed
> and related workqueue name.
>
> A final good probing approach could be interesting to be added to
> "scheduler" examples. I am "happy" with mine but experts can probably
> improve.
Yes, please share -- we like getting new examples, as many people start
by only running those scripts.
Thanks,
Josh