Some newbie questions

Avi Kivity avi@scylladb.com
Tue Aug 9 06:51:00 GMT 2016



On 08/08/2016 05:58 PM, David Smith wrote:
>
>> 2. Inlined functions
>>
>>  From the manual pages, it seems that inlined functions can be probed
>> (minus the .return probe), but I just get an error:
>>
>> semantic error: while resolving probe point: identifier 'process' at
>> script/home/avi/seastar/debug/task-latency.stap:3:7
>>          source: probe process("scylla").function("reactor::run_tasks()") {
>>                        ^
>>
>> semantic error: no match (similar functions:
>> _ZN7reactor14run_exit_tasksEv, statfs, dup, mkdir, ntohs)
> We're at the mercy of the compiler and the quality of the debuginfo it
> produces here when looking for inlined functions.
>
> If you want to investigate further here, you'll need to do the following:
>
> # eu-readelf -N --debug-dump=info scylla > scylla.log
>
> In scylla.log, look and see if you can find a subprogram with the name
> of the function you are interested in.

  [1417f4]      subprogram
                external             (flag_present) Yes
                name                 (strp) "run_tasks"
                decl_file            (data1) 5
                decl_line            (data2) 812
                linkage_name         (strp) 
"_ZN7reactor9run_tasksER15circular_bufferISt10unique_ptrI4taskSt14default_deleteIS2_EESaIS5_EE"
                declaration          (flag_present) Yes
                object_pointer       (ref4) [141808]
                sibling              (ref4) [141813]
  [141808]        formal_parameter
                  type                 (ref4) [1423bd]
                  artificial           (flag_present) Yes
  [14180d]        formal_parameter
                  type                 (ref4) [14a8a8]


The debugger has no trouble setting breakpoints on the function or 
showing it in backtraces.  In any case I sprinkled some static probes there.

>> 3. Process CPU timers
>>
>> (more of a feature request)
>>
>> I'm trying to find causes of latency in my program.  To do that, I'm
>> running a periodic timer and checking whether a function takes more time
>> than some threshold.
>>
>> Ideally, I'd be able to arm the timer on the function entry point and
>> disarm it on exit, rather than have it run continuously; this would need
>> to be a per-thread cpu-time timer (e.g. CLOCK_THREAD_CPUTIME_ID)/
>>
>> Here's my current script for reference ("running" and "start_time" need
>> to become maps for it to be thread-safe):
>>
>> #!/usr/bin/stap
>>
>> global start_time
>> global running
>>
>> probe begin {
>>      running = 0
>> }
>>
>> probe
>> process("/home/avi/urchin/build/release/scylla").mark("reactor_run_tasks_start")
>> {
>>      start_time = gettimeofday_us()
>>      running = 1
>> }
>>
>> probe
>> process("/home/avi/urchin/build/release/scylla").mark("reactor_run_tasks_end")
>> {
>>      running = 0
>> }
>>
>> probe timer.ms(10) {
>>      now = gettimeofday_us()
>>      if (running && (now - start_time) > 30000) {
>>          printf("detected tasks running for >30ms\n")
>>          print_usyms(ubacktrace())
>>      }
>> }
>>
>> I'd appreciate any tips as to whether there's a better way to do this.
> The above isn't really going to work well, for several reasons:
>
> 1) You've only got one global 'start_time' and 'running' variables. If
> scylla is multithreaded or more than one instance is running, that isn't
> going to work.
>
> To fix this, you'd want to do convert them to arrays and index them by
> thread ids, like this:
>
>      start_time[tid()] = gettimeofday_us()

Yes, I found that out and my latest version works like this, but I ran 
into severe scaling issues.

I also switched to timer.profile.  What's its resolution on normal machines?

> 2) Your ubacktrace() call in the timer function isn't going to report
> what you want. At that point, you aren't running in the context of the
> process, you are running in the context of whatever kernel thread is
> running the timer. I'm really sure what a user backtrace will report at
> that point, but it certainly won't be useful.

Actually I got good backtraces when I instrumented a task to spin for 
100ms.  I also got some bad traces, but did not investigate more.

> Here's an (untested) version of what would work a bit better:
>
> ====
> global start_time
>
> probe
> process("/home/avi/urchin/build/release/scylla").mark("reactor_run_tasks_start")
> {
>      start_time[tid()] = gettimeofday_us()
> }
>
> probe
> process("/home/avi/urchin/build/release/scylla").mark("reactor_run_tasks_end")
> {
>      now = gettimeofday_us()
>      start = start_time[tid()]
>      delete start_time[tid()]
>      if ((now - start) > 30000) {
>           printf("detected tasks running for >30ms (%d)\n",
>                  (now - start))
>           print_usyms(ubacktrace())

Here the backtrace is useless, I know exactly what it looks like at this 
point; it's two frames away from main().

To give some context, this is a run-to-completion scheduler. I have 
tasks pushed into a queue from various sources (including other tasks), 
and this bit is the part of the main loop that dequeues a task, runs it, 
and repeats.  Some tasks take too long, and I want to identify which 
ones.  I could print the last task's vtable, but that is much less 
useful than a full backtrace at the time the task is detected as taking 
too long.


>      }
> }
> ====
>
> If you like, you could add a timer probe to the above to report an
> ongoing problem in the current process (but without printing a backtrace).
>

Unfortunately I already know there is a problem and need to pinpoint 
it.  Which is where the backtrace is so useful.

I can fall back to instrumenting the code with a timer (from 
timer_create(3)), but I'd much rather have the flexibility of 
non-intrusive instrumentation.



More information about the Systemtap mailing list