DTrace integration features

This post explores my troubles with integrating DTrace in projects. I spent a few days searching for and fixing bugs in DTrace. I'll explain my troubles and approach to fixing bugs in tarantool, a no-sql DB, with common instruments.

This post isn't yet complete. I'll add new information after fix/found bugs.

Instruments to research:

OSs:

Solaris based:

DTrace Versions:

Generate DTrace object twice

%> sudo dtrace -l -m tarantool_box
Password:
   ID   PROVIDER            MODULE                          FUNCTION NAME
dtrace: failed to match :tarantool_box::: No probe matches description

If you have a modular application you'll try to generate many dtrace objects to link that with the application. You get static libraries and then link. This is a common approach to programming but if you use DTrace in more than one library you need run dtrace -G to get one dtrace object which include all providers.

After the first time you get a dtrace object with correct information but you would like to get object for all providers in different libs in one object. I'll explain the main issue with second generation with an example.

This is an example with one library. You are able to do this on the command line for getting incorrect object because you did correct object before with information about one: ***

%> dtrace -G -s ../../include/dtrace.d ../CMakeFiles/cjson.dir/third_party/lua-cjson/lua_cjson.c.o -o cjson_dtrace_second.o

%> md5 cjson_dtrace.o
MD5 (cjson_dtrace.o) = 69cc9d1037f106e682464af05205458c
%> md5 cjson_dtrace_second.o
MD5 (cjson_dtrace_second.o) = a42c72ae540be068243936afe2d7b868

On above list you see mismatched md5 sums. When I found that I started fire to drill-down to object files and look at what's incorrect.

I got 2 dtrace objects, Using the strings command I found the differences:

%> strings -a cjson_dtrace_second.o > dtrace_second
%> strings -a cjson_dtrace.o > dtrace
%> diff -up dtrace dtrace_second

I saw removed functions with dtrace defines for a trace.

--- dtrace  2013-09-27 13:47:17.839671510 +0000
+++ dtrace_second   2013-09-27 13:47:08.717669720 +0000
@@ -117,15 +117,10 @@ vfprintf
 encode-done
 char *
 char *
-json_encode
-$dtrace140912.json_encode
 encode-start
 char *
 char *
-json_encode
-$dtrace140912.json_encode
 new-entry
-luaopen_cjson
 tick-start
 tick-stop
 tarantool

In the next stage I looked inside .SUNW_dof in section of dtrace object file.

%> objdump -s -j .SUNW_dof cjson_dtrace.o

This is correct hex output from dtrace object:

cjson_dtrace.o:     file format elf64-x86-64-freebsd

Contents of section .SUNW_dof:
 0270 00000000 00000000 00000000 05000000  ................
 0280 01000000 00656e63 6f64652d 646f6e65  .....encode-done
 0290 00696e74 00636861 72202a00 696e7400  .int.char *.int.
 02a0 63686172 202a006a 736f6e5f 656e636f  char *.json_enco
 02b0 64650024 64747261 63653134 30393132  de.$dtrace140912
 02c0 2e6a736f 6e5f656e 636f6465 00656e63  .json_encode.enc
 02d0 6f64652d 73746172 7400696e 74006368  ode-start.int.ch
 02e0 6172202a 00696e74 00636861 72202a00  ar *.int.char *.
 02f0 6a736f6e 5f656e63 6f646500 24647472  json_encode.$dtr
 0300 61636531 34303931 322e6a73 6f6e5f65  ace140912.json_e
 0310 6e636f64 65006e65 772d656e 74727900  ncode.new-entry.
 0320 6c75616f 70656e5f 636a736f 6e007469  luaopen_cjson.ti
 0330 636b2d73 74617274 00696e74 00696e74  ck-start.int.int
 0340 00746963 6b2d7374 6f700069 6e740069  .tick-stop.int.i
 0350 6e740074 6172616e 746f6f6c 00000000  nt.tarantool....
 0360 53756e20 4420312e 37004672 65654253  Sun D 1.7.FreeBS
 0370 44000000 00000000 00000000 00000000  D...............
 0380 00000000 00000000 00000000 00000000  ................

Drill-down to next incorrect object:

%> objdump -s -j .SUNW_dof cjson_dtrace_second.o

In .SUNW_dof sect I saw empty dtrace providers for tracing function:

cjson_dtrace_second.o:     file format elf64-x86-64-freebsd

Contents of section .SUNW_dof:
 0190 00000000 00000000 00000000 05000000  ................
 01a0 01000000 00656e63 6f64652d 646f6e65  .....encode-done
 01b0 00696e74 00636861 72202a00 696e7400  .int.char *.int.
 01c0 63686172 202a0065 6e636f64 652d7374  char *.encode-st
 01d0 61727400 696e7400 63686172 202a0069  art.int.char *.i
 01e0 6e740063 68617220 2a006e65 772d656e  nt.char *.new-en
 01f0 74727900 7469636b 2d737461 72740069  try.tick-start.i
 0200 6e740069 6e740074 69636b2d 73746f70  nt.int.tick-stop
 0210 00696e74 00696e74 00746172 616e746f  .int.int.taranto
 0220 6f6c0000 00000000 53756e20 4420312e  ol......Sun D 1.
 0230 37004672 65654253 44000000 00000000  7.FreeBSD.......
 0240 00000000 00000000 00000000 00000000  ................

The next step is finding differences in library objects. After running dtrace -G twice I get these changes in main library objects:

%> md5 lua_cjson.c.o
MD5 (lua_cjson.c.o) = bdc0afbb0869f7bee70c29a7ba538127
%> md5 lua_cjson.c.o.dtrace
MD5 (lua_cjson.c.o.dtrace) = 0d65212c87350dceb64f71429b72ce3b

I looked at the .text section of the object file in objdump because this section contains the executible code.

%> objdump -d -j .text lua_cjson.c.o.dtrace > dtrace
%> objdump -d -j .text lua_cjson.c.o > non-dtrace

I used the diff command to confirm that the changes are correct:

%> diff -up non-dtrace dtrace
--- non-dtrace  2013-09-27 13:42:05.811669039 +0000
+++ dtrace  2013-09-27 13:41:59.149669338 +0000
@@ -1,5 +1,5 @@

-lua_cjson.c.o:     file format elf64-x86-64-freebsd
+lua_cjson.c.o.dtrace:     file format elf64-x86-64-freebsd

 Disassembly of section .text:

@@ -11,7 +11,11 @@ Disassembly of section .text:
        c:  48 8b 7d f8             mov    -0x8(%rbp),%rdi
       10:  e8 1b 00 00 00          callq  30 <lua_cjson_new>
       15:  89 45 f4                mov    %eax,-0xc(%rbp)
-      18:  e8 00 00 00 00          callq  1d <luaopen_cjson+0x1d>
+      18:  90                      nop
+      19:  90                      nop
+      1a:  90                      nop
+      1b:  90                      nop
+      1c:  90                      nop
       1d:  b8 01 00 00 00          mov    $0x1,%eax
       22:  48 83 c4 10             add    $0x10,%rsp
       26:  5d                      pop    %rbp
@@ -217,7 +221,7 @@ Disassembly of section .text:
      34b:  c3                      retq
      34c:  0f 1f 40 00             nopl   0x0(%rax)

-0000000000000350 <json_encode>:
+0000000000000350 <$dtrace140912.json_encode>:
      350:  55                      push   %rbp
      351:  48 89 e5                mov    %rsp,%rbp
      354:  48 83 ec 50             sub    $0x50,%rsp
@@ -227,18 +231,22 @@ Disassembly of section .text:
      365:  48 89 45 f0             mov    %rax,-0x10(%rbp)
      369:  8b 7d bc                mov    -0x44(%rbp),%edi
      36c:  48 8b 75 c0             mov    -0x40(%rbp),%rsi
-     370:  e8 00 00 00 00          callq  375 <json_encode+0x25>
+     370:  90                      nop
+     371:  90                      nop
+     372:  90                      nop
+     373:  90                      nop
+     374:  90                      nop
      375:  48 8b 7d f8             mov    -0x8(%rbp),%rdi
-     379:  e8 00 00 00 00          callq  37e <json_encode+0x2e>
+     379:  e8 00 00 00 00          callq  37e <$dtrace140912.json_encode+0x2e>
      37e:  b1 01                   mov    $0x1,%cl
      380:  3d 01 00 00 00          cmp    $0x1,%eax
      385:  88 4d bb                mov    %cl,-0x45(%rbp)
-     388:  0f 84 21 00 00 00       je     3af <json_encode+0x5f>
+     388:  0f 84 21 00 00 00       je     3af <$dtrace140912.json_encode+0x5f>
      38e:  be 01 00 00 00          mov    $0x1,%esi
      393:  48 8d 14 25 00 00 00    lea    0x0,%rdx
      39a:  00
      39b:  48 8b 7d f8             mov    -0x8(%rbp),%rdi
-     39f:  e8 00 00 00 00          callq  3a4 <json_encode+0x54>
+     39f:  e8 00 00 00 00          callq  3a4 <$dtrace140912.json_encode+0x54>
      3a4:  3d 00 00 00 00          cmp    $0x0,%eax
      3a9:  0f 95 c1                setne  %cl
      3ac:  88 4d bb                mov    %cl,-0x45(%rbp)
@@ -247,13 +255,13 @@ Disassembly of section .text:
      3b6:  81 b9 38 05 00 00 00    cmpl   $0x0,0x538(%rcx)
      3bd:  00 00 00
      3c0:  88 45 ba                mov    %al,-0x46(%rbp)
-     3c3:  0f 85 1b 00 00 00       jne    3e4 <json_encode+0x94>
+     3c3:  0f 85 1b 00 00 00       jne    3e4 <$dtrace140912.json_encode+0x94>
      3c9:  be 00 00 00 00          mov    $0x0,%esi
      3ce:  48 8d 45 d0             lea    -0x30(%rbp),%rax
      3d2:  48 89 45 c8             mov    %rax,-0x38(%rbp)
      3d6:  48 8b 7d c8             mov    -0x38(%rbp),%rdi
-     3da:  e8 00 00 00 00          callq  3df <json_encode+0x8f>
-     3df:  e9 17 00 00 00          jmpq   3fb <json_encode+0xab>
+     3da:  e8 00 00 00 00          callq  3df <$dtrace140912.json_encode+0x8f>
+     3df:  e9 17 00 00 00          jmpq   3fb <$dtrace140912.json_encode+0xab>
      3e4:  48 8b 45 f0             mov    -0x10(%rbp),%rax
      3e8:  48 05 00 05 00 00       add    $0x500,%rax
      3ee:  48 89 45 c8             mov    %rax,-0x38(%rbp)
@@ -271,16 +279,20 @@ Disassembly of section .text:
      422:  48 8b 7d f8             mov    -0x8(%rbp),%rdi
      426:  48 8b 75 c0             mov    -0x40(%rbp),%rsi
      42a:  48 63 55 bc             movslq -0x44(%rbp),%rdx
-     42e:  e8 00 00 00 00          callq  433 <json_encode+0xe3>
+     42e:  e8 00 00 00 00          callq  433 <$dtrace140912.json_encode+0xe3>
      433:  48 8b 45 f0             mov    -0x10(%rbp),%rax
      437:  81 b8 38 05 00 00 00    cmpl   $0x0,0x538(%rax)
      43e:  00 00 00
-     441:  0f 85 09 00 00 00       jne    450 <json_encode+0x100>
+     441:  0f 85 09 00 00 00       jne    450 <$dtrace140912.json_encode+0x100>
      447:  48 8b 7d c8             mov    -0x38(%rbp),%rdi
-     44b:  e8 00 00 00 00          callq  450 <json_encode+0x100>
+     44b:  e8 00 00 00 00          callq  450 <$dtrace140912.json_encode+0x100>
      450:  8b 7d bc                mov    -0x44(%rbp),%edi
      453:  48 8b 75 c0             mov    -0x40(%rbp),%rsi
-     457:  e8 00 00 00 00          callq  45c <json_encode+0x10c>
+     457:  90                      nop
+     458:  90                      nop
+     459:  90                      nop
+     45a:  90                      nop
+     45b:  90                      nop
      45c:  b8 01 00 00 00          mov    $0x1,%eax
      461:  48 83 c4 50             add    $0x50,%rsp
      465:  5d                      pop    %rbp

As seen above, DTrace modifies an object file with use together dtrace and library objects.

Doesn't work multi-PROVIDER in MODULE

This is the next main issue with integration. It doesn't work on anything providers in one module (application). I always got one working provider in application. The trouble related to many dtrace objects which I wanted use when I linked application. If you have a few dtrace objects I'll link its in binary but works only first provider (depended by position object file in linking proccess).*****

%> cat ../include/dtrace.d

Main providers from dtrace file:

provider coro {
    probe new__entry();
};
provider ev {
    probe tick__start(int flags);
    probe tick__stop(int flags);
};
provider cjson {
    probe encode__start(int len, char *);
    probe encode__done(int len, char *);
    probe new__entry(void *);
};

It doesn't work because we need to run DTrace twice. See “Generate DTrace object twice” for more details.

%> dtrace -G  -x nolibs -s ../include/dtrace.d  CMakeFiles/ev.dir/third_party/tarantool_ev.c.o CMakeFiles/coro.dir/third_party/coro/coro.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/fpconv.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/lua_cjson.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/strbuf.c.o

%> dtrace -G  -s ../include/dtrace.d  CMakeFiles/ev.dir/third_party/tarantool_ev.c.o CMakeFiles/coro.dir/third_party/coro/coro.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/fpconv.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/lua_cjson.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/strbuf.c.o -o probes.o

%> md5 probes.o dtrace.o
MD5 (probes.o) = bc2c205b019c5e948cfba89ff098c7e8
MD5 (dtrace.o) = bc2c205b019c5e948cfba89ff098c7e8

I split the dtrace file into several .d files. After that I got a few dtrace objects from correct object files.

%> dtrace -G  -s ../include/dtrace.d  CMakeFiles/cjson.dir/third_party/lua-cjson/fpconv.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/lua_cjson.c.o CMakeFiles/cjson.dir/third_party/lua-cjson/strbuf.c.o -o dtrace/cjson_dtrace.o

%> cat ../third_party/lua-cjson/cjson_dtrace.d
provider cjson {
    probe encode__start(int len, char *);
    probe encode__done(int len, char *);
    probe new__entry(void *);
};
%> dtrace -G  -s ../third_party/libev/ev_dtrace.d  CMakeFiles/ev.dir/third_party/tarantool_ev.c.o -o dtrace/ev_dtrace.o

%> cat ../third_party/libev/ev_dtrace.d
provider ev {
    probe tick__start(int flags);
    probe tick__stop(int flags);
};
%> dtrace -G  -s ../third_party/coro/coro_dtrace.d  CMakeFiles/coro.dir/third_party/coro/coro.c.o -o dtrace/coro_dtrace.o
%> cat ../third_party/coro/coro_dtrace.d
provider coro {
    probe new__entry();
};

It worked when I linked one dtrace object at the end of line:

%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/cjson_dtrace.o

Providers works in module:

%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571 cjson43089     tarantool_box                       json_encode encode-done
56572 cjson43089     tarantool_box                       json_encode encode-start
56573 cjson43089     tarantool_box                     luaopen_cjson new-entry
56574 cjson43090     tarantool_box                       json_encode encode-done
56575 cjson43090     tarantool_box                       json_encode encode-start
56576 cjson43090     tarantool_box                     luaopen_cjson new-entry
%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/ev_dtrace.o
%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571    ev42775     tarantool_box                            ev_run tick-start
56572    ev42775     tarantool_box                            ev_run tick-stop
56573    ev42776     tarantool_box                            ev_run tick-start
56574    ev42776     tarantool_box                            ev_run tick-stop
%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/core_dtrace.o

``` sh
%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571  coro43386     tarantool_box                         coro_init new-entry
56572  coro43387     tarantool_box                         coro_init new-entry

This shows the main issue with linking all *.o dtrace objects. If want try that You'll get only one working provider because it is linked with sorted objects and first is cjson alphabetically .

%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/*.o
%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571 cjson43681     tarantool_box                       json_encode encode-done
56572 cjson43681     tarantool_box                       json_encode encode-start
56573 cjson43681     tarantool_box                     luaopen_cjson new-entry
56574 cjson43682     tarantool_box                       json_encode encode-done
56575 cjson43682     tarantool_box                       json_encode encode-start
56576 cjson43682     tarantool_box                     luaopen_cjson new-entry
%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/coro_dtrace.o ../../dtrace/ev_dtrace.o ../../dtrace/cjson_dtrace.o
%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571  coro43978     tarantool_box                         coro_init new-entry
56572  coro43979     tarantool_box                         coro_init new-entry
%> /usr/local/bin/clang++33    -fno-omit-frame-pointer -fno-stack-protector -fexceptions -funwind-tables -std=c++11 -fno-rtti -Wall -Wextra -Wno-sign-compare -Wno-strict-aliasing    CMakeFiles/tarantool_box.dir/tuple.cc.o CMakeFiles/tarantool_box.dir/tuple_convert.cc.o CMakeFiles/tarantool_box.dir/tuple_update.cc.o CMakeFiles/tarantool_box.dir/key_def.cc.o CMakeFiles/tarantool_box.dir/index.cc.o CMakeFiles/tarantool_box.dir/hash_index.cc.o CMakeFiles/tarantool_box.dir/tree_index.cc.o CMakeFiles/tarantool_box.dir/bitset_index.cc.o CMakeFiles/tarantool_box.dir/space.cc.o CMakeFiles/tarantool_box.dir/port.cc.o CMakeFiles/tarantool_box.dir/request.cc.o CMakeFiles/tarantool_box.dir/txn.cc.o CMakeFiles/tarantool_box.dir/box.cc.o CMakeFiles/tarantool_box.dir/lua/box.lua.c.o CMakeFiles/tarantool_box.dir/lua/box_net.lua.c.o CMakeFiles/tarantool_box.dir/lua/misc.lua.c.o CMakeFiles/tarantool_box.dir/lua/sql.lua.c.o CMakeFiles/tarantool_box.dir/box_lua.cc.o CMakeFiles/tarantool_box.dir/box_lua_space.cc.o CMakeFiles/tarantool_box.dir/__/__/cfg/tarantool_box_cfg.c.o -o tarantool_box libltbox.a ../../cfg/libcfg.a ../libcore.a ../../libev.a ../../libeio.a ../../libcoro.a ../../libgopt.a ../../libcjson.a ../../third_party/luajit/src/libluajit.a ../../libmisc.a -lpthread -lintl -lelf ../lib/bitset/libbitset.a ../lib/bit/libbit.a -L/usr/local/lib ../../dtrace/ev_dtrace.o ../../dtrace/coro_dtrace.o ../../dtrace/cjson_dtrace.o
%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
56571    ev44268     tarantool_box                            ev_run tick-start
56572    ev44268     tarantool_box                            ev_run tick-stop
56573    ev44269     tarantool_box                            ev_run tick-start
56574    ev44269     tarantool_box                            ev_run tick-stop

The issue is solved with use one common dtrace object for all libs. You need to run:

dtrace -G -s file.d *.o -o common.o

And then link libs, objects and common.o to the binary.

Wildcards don't work.

I fixed first issue. Wildcards do not work for all providers.

Ready to use providers in module:

%> sudo dtrace -l -m tarantool_box
   ID   PROVIDER            MODULE                          FUNCTION NAME
 2789  coro23800     tarantool_box                         coro_init new-entry
 2790    ev23800     tarantool_box                            ev_run tick-start
 2791    ev23800     tarantool_box                            ev_run tick-stop
 2792 cjson23800     tarantool_box                       json_encode encode-done
 2793 cjson23800     tarantool_box                       json_encode encode-start
 2893  coro23798     tarantool_box                         coro_init new-entry
 2894    ev23798     tarantool_box                            ev_run tick-start
 2895    ev23798     tarantool_box                            ev_run tick-stop
 2896 cjson23798     tarantool_box                       json_encode encode-done
 2897 cjson23798     tarantool_box                       json_encode encode-start

If I had file.d which contained:

provider cjson {
    probe new__entry();
    probe encode__start();
    probe encode__done(int len, char *);
};
provider coro {
    probe new__entry();
};
provider ev {
    probe tick__start(int flags);
    probe tick__stop(int flags);
};

I would got only one working cjson*::

%> sudo dtrace -n 'cjson*::json_encode:encode-done'
dtrace: description 'cjson*::json_encode:encode-done' matched 2 probes
CPU     ID                    FUNCTION:NAME
 1      4          json_encode:encode-done
 0      4          json_encode:encode-done
 1      4          json_encode:encode-done
 1      4          json_encode:encode-done
^C

Empty results for another provider in the module:

%> sudo dtrace -n coro*:::

^C

The trouble relates to position providers in file.d.

Not fixed in FreeBSD, You have to use one name for all providers:

%> sudo dtrace -l -m tarantool_box
   ID   PROVIDER            MODULE                          FUNCTION NAME
56571 tarantool75366     tarantool_box                       json_encode encode-done
56572 tarantool75366     tarantool_box                       json_encode encode-start
56573 tarantool75366     tarantool_box                     luaopen_cjson new-entry
56574 tarantool75366     tarantool_box                         coro_init new-entry
56575 tarantool75366     tarantool_box                            ev_run tick-start
56576 tarantool75366     tarantool_box                            ev_run tick-stop
56577 tarantool75367     tarantool_box                       json_encode encode-done
56578 tarantool75367     tarantool_box                       json_encode encode-start
56579 tarantool75367     tarantool_box                     luaopen_cjson new-entry
56580 tarantool75367     tarantool_box                         coro_init new-entry
56581 tarantool75367     tarantool_box                            ev_run tick-start
56582 tarantool75367     tarantool_box                            ev_run tick-stop

All the providers must use the code

If you defined a lot of providers in the D file, but some of providers doesn't use the code, then all providers doesn't work.

For example you have:

provider lua_cjson {
       probe start();
       probe end(int, char *);
};
provider coro {
       probe new__entry();
};
provider ev {
       probe tick__start(int flags);
       probe tick__stop(int flags);
}

But providers lua_cjson and coro doesn't use in code but defined in D file. You'll have:

%> sudo dtrace -l -m tarantool_box
Password:
   ID   PROVIDER            MODULE                          FUNCTION NAME
dtrace: failed to match :tarantool_box::: No probe matches description

If you change file as below:

provider ev {
       probe tick__start(int flags);
       probe tick__stop(int flags);
};

Then run tarantool again you'll have:

%> sudo dtrace -l -m tarantool_box
   ID   PROVIDER            MODULE                          FUNCTION NAME
56642    ev32305     tarantool_box                            ev_run tick-start
56643    ev32305     tarantool_box                            ev_run tick-stop

This is bug on FreeBSD and Oracle Linux.

Kernel panic by empty MODULE

If you run application You'll get access to providers:

%> sudo dtrace -l -m tarantool_box
  ID   PROVIDER            MODULE                          FUNCTION NAME
   4  cjson2015     tarantool_box                       json_encode encode-done
   5  cjson2015     tarantool_box                       json_encode encode-start
   6  cjson2015     tarantool_box                     luaopen_cjson new-entry
   7   coro2015     tarantool_box                         coro_init new-entry
   8     ev2015     tarantool_box                            ev_run tick-start
   9     ev2015     tarantool_box                            ev_run tick-stop
  10  cjson2016     tarantool_box                       json_encode encode-done
  11  cjson2016     tarantool_box                       json_encode encode-start
  12  cjson2016     tarantool_box                     luaopen_cjson new-entry
  13   coro2016     tarantool_box                         coro_init new-entry
  14     ev2016     tarantool_box                            ev_run tick-start
  15     ev2016     tarantool_box                            ev_run tick-stop

But If you run dtrace -m tarantool_box and then shutdown tarantool_box You'll get a kernel panic:

#>  kgdb kernel.debug /var/crash/vmcore.0
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-marcel-freebsd"...

Unread portion of the kernel message buffer:
kernel trap 12 with interrupts disabled


Fatal trap 12: page fault while in kernel mode
cpuid = 1; apic id = 01
fault virtual address   = 0xfffffdffd8ecf3e2
fault code      = supervisor read data, page not present
instruction pointer = 0x20:0xffffffff81a4a7fd
stack pointer           = 0x28:0xffffff80d53119d0
frame pointer           = 0x28:0xffffff80d53119f0
code segment        = base 0x0, limit 0xfffff, type 0x1b
            = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags    = resume, IOPL = 1
current process     = 2023 (tarantool_box)
trap number     = 12
panic: page fault
cpuid = 1
KDB: stack backtrace:
#0 0xffffffff809538a6 at kdb_backtrace+0x66
#1 0xffffffff8091ac8e at panic+0x1ce
#2 0xffffffff80c17990 at trap_fatal+0x290
#3 0xffffffff80c17cfc at trap_pfault+0x21c
#4 0xffffffff80c182f5 at trap+0x365
#5 0xffffffff80c025f3 at calltrap+0x8
#6 0xffffffff81cb15fd at fasttrap_fork+0x27d
#7 0xffffffff808eaea9 at fork1+0x1519
#8 0xffffffff808ebc12 at sys_fork+0x22
#9 0xffffffff80c1713a at amd64_syscall+0x5ea
#10 0xffffffff80c028d7 at Xfast_syscall+0xf7
Uptime: 5m12s
Dumping 356 out of 3001 MB:..5%..14%..23%..32%..41%..54%..63%..72%..81%..95%

.... Loading modules skipped ....

#0  doadump (textdump=Variable "textdump" is not available.
) at pcpu.h:224
224     __asm("movq %%gs:0,%0" : "=r" (td));
(kgdb) list *0xffffffff81a4a7fd
0xffffffff81a4a7fd is in dtrace_assfail (/usr/src/sys/modules/dtrace/dtrace/../../../cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c:603).
598 }
599
600 int
601 dtrace_assfail(const char *a, const char *f, int l)
602 {
603     dtrace_panic("assertion failed: %s, file: %s, line: %d", a, f, l);
604
605     /*
606      * We just need something here that even the most clever compiler
607      * cannot optimize away.
(kgdb) backtrace
#0  doadump (textdump=Variable "textdump" is not available.
) at pcpu.h:224
#1  0xffffffff8091a771 in kern_reboot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:448
#2  0xffffffff8091ac67 in panic (fmt=0x1 <Address 0x1 out of bounds>) at /usr/src/sys/kern/kern_shutdown.c:636
#3  0xffffffff80c17990 in trap_fatal (frame=0xc, eva=Variable "eva" is not available.
) at /usr/src/sys/amd64/amd64/trap.c:857
#4  0xffffffff80c17cfc in trap_pfault (frame=0xffffff80d5311920, usermode=0) at /usr/src/sys/amd64/amd64/trap.c:773
#5  0xffffffff80c182f5 in trap (frame=0xffffff80d5311920) at /usr/src/sys/amd64/amd64/trap.c:456
#6  0xffffffff80c025f3 in calltrap () at /usr/src/sys/amd64/amd64/exception.S:228
#7  0xffffffff81a4a7fd in dtrace_assfail (a=0xffffffff81cb4bc6 "cp->p_dtrace_count == 0", f=0xfffffe005721a81c "coro*", l=Variable "l" is not available.
)
    at /usr/src/sys/modules/dtrace/dtrace/../../../cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c:603
#8  0xffffffff81cb15fd in fasttrap_fork (p=0xfffffe00a83b64a0, cp=0xfffffe005711d940)
    at /usr/src/sys/modules/dtrace/fasttrap/../../../cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c:479
#9  0xffffffff808eaea9 in fork1 (td=0xfffffe002b730470, flags=20, pages=Variable "pages" is not available.
) at /usr/src/sys/kern/kern_fork.c:694
#10 0xffffffff808ebc12 in sys_fork (td=0xfffffe002b730470, uap=Variable "uap" is not available.
) at /usr/src/sys/kern/kern_fork.c:110
#11 0xffffffff80c1713a in amd64_syscall (td=0xfffffe002b730470, traced=0) at subr_syscall.c:135
#12 0xffffffff80c028d7 in Xfast_syscall () at /usr/src/sys/amd64/amd64/exception.S:387
#13 0x0000000801731a7c in ?? ()

Mark Johnston send me FIX panic. I am planing to try the patch.

CMake automation

Integration with CMake or another build tools is painful because you need do dtrace -G for one or many objects. But that is not needed on on OSX, this is the best way and more convenient. See example with full hack linking to library/binary:

set(cjson_obj)

add_library(cjson_objs OBJECT lua_cjson.c strbuf.c ${FPCONV_SOURCES})
set_target_properties(cjson_objs PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(cjson_obj ${cjson_obj} $<TARGET_OBJECTS:cjson_objs>)

if(ENABLE_DTRACE AND DTRACE)
    message(STATUS "DTrace found and enabled")
    add_definitions(-DENABLE_DTRACE)
    set(D_FILE ${PROJECT_SOURCE_DIR}/cjson_dtrace)
    execute_process(
       COMMAND ${DTRACE} -h -s ${D_FILE}.d -o ${D_FILE}.h
    )
    if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
        set(cjson_obj_2 ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/cjson_objs.dir/lua_cjson.c.o)
        set(dtrace_obj ${CMAKE_CURRENT_BINARY_DIR}/dtrace.o)
        add_custom_command(OUTPUT ${dtrace_obj}
            COMMAND ${DTRACE} -G -s ${D_FILE}.d -o ${dtrace_obj} ${cjson_obj_2}
            DEPENDS ${cjson_obj_2}
        )
        set_source_files_properties(${dtrace_obj}
            PROPERTIES
            EXTERNAL_OBJECT true
            GENERATED true
        )
        set(cjson_obj ${cjson_obj} ${dtrace_obj})
        unset(cjson_obj_2)
        unset(dtrace_obj)
        unset(D_FILE)
    endif()
endif()

add_library(cjson MODULE ${cjson_obj})
set_target_properties(cjson PROPERTIES PREFIX "")
target_link_libraries(cjson ${_MODULE_LINK})

DTrace in tarantool

A pre-release of DTrace is available in tarantool. If you run box.cjson.encode() function, You'll able to see data for encoding and len.

Example commands in command line tarantool client:

127.0.0.2> lua box.cjson.encode({test= 'xzvfvzcvzx'})
---
 - {"test":"xzvfvzcvzx"}
...
127.0.0.2> lua box.cjson.encode({test= 'xzvfvzcvzx'})
---
 - {"test":"xzvfvzcvzx"}
...
127.0.0.2> lua box.cjson.encode({test= 'xzvfvzcvzx'})
---
 - {"test":"xzvfvzcvzx"}
...
127.0.0.2> lua box.cjson.encode({test= 'xzvfvzsafzx'})
---
 - {"test":"xzvfvzsafzx"}
...
127.0.0.2> lua box.cjson.encode({test= 'xx'})
---
 - {"test":"xx"}
...
127.0.0.2> lua box.cjson.encode({tmasfasdf= 'xx'})
---
 - {"tmasfasdf":"xx"}
...

DTrace in action:

%> sudo dtrace -n 'tarantool*:json_encode:encode-start { self->ts = timestamp; } tarantool*:json_encode:encode-done { printf("%s time: %d", copyinstr(arg1),
 ((timestamp - self->ts)/1000)); }'
dtrace: description 'tarantool*:json_encode:encode-start ' matched 4 probes
CPU     ID                    FUNCTION:NAME
  1  56611          json_encode:encode-done {"test":"xzvfvzcvzx"}x"} time: 10
  1  56611          json_encode:encode-done {"test":"xzvfvzcvzx"}x"} time: 10
  1  56611          json_encode:encode-done {"test":"xzvfvzcvzx"}x"} time: 7
  1  56611          json_encode:encode-done {"test":"xzvfvzsafzx"}"} time: 10
  1  56611          json_encode:encode-done {"test":"xx"}vzsafzx"}"} time: 9
  1  56611          json_encode:encode-done {"tmasfasdf":"xx"}zx"}"} time: 9

Patched tarantool available in the repo tarantool-dtrace.

DTrace probes at runtime

This is very intersting task, I found libusdt with lua-usdt bindings and tried that in tarantool-dtrace. I had great result on OSX and FreeBSD but on Oracle Linux doesn't work.

Exaple of usage:

After you run the application you have only static providers:

%> sudo dtrace -l -m tarantool_box
   ID   PROVIDER            MODULE                          FUNCTION NAME
 1578   lua54178     tarantool_box                               foo iprobe
 4031    ev54179     tarantool_box                            ev_run tick-start
 4032    ev54179     tarantool_box                            ev_run tick-stop
 4132    ev54178     tarantool_box                            ev_run tick-start
 4133    ev54178     tarantool_box                            ev_run tick-stop

Then connect and try to use a USDT providers at realtime:

%> ~/tmp/tt-dtrace/bin/tarantool
localhost> usdt
---
- provider: 'function: 0x094ca2b0'
...
localhost> provider = usdt.provider("lua", "tarantool_box")
---
...
localhost> iprobe = provider:probe("foo", "iprobe", "int")
---
...
localhost> provider:enable()
---
...

If you run DTrace you'll see available probes at realtime:

%> sudo dtrace -n 'lua*:tarantool_box:foo:iprobe { printf("%d", arg0)}'
dtrace: description 'lua*:tarantool_box:foo:iprobe ' matched 1 probe

Time to fire!

localhost> iprobe:fire(1)
---
...
localhost> iprobe:fire(2)
---
...
localhost> iprobe:fire(4)
---
...
localhost> iprobe:fire(200)
---
...
localhost>

You must see probes at realtime:

%> sudo dtrace -n 'lua*:tarantool_box:foo:iprobe { printf("%d", arg0)}'
dtrace: description 'lua*:tarantool_box:foo:iprobe ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  1   1578                       foo:iprobe 1
  0   1578                       foo:iprobe 2
  1   1578                       foo:iprobe 4
  1   1578                       foo:iprobe 200

Unfortunately doesn't work on Oracle Linux. Also FreeBSD have a bug with USDT probes where probes more than 5 arguments.

DTrace on FreeBSD

DTrace has a lot of bugs but it works with some limits.

Bug list:

DTrace on Oracle Linux

DTrace on Oracle Linux doesn't work well. I found a few bugs similar as on FreeBSD.

Bug list:

DTrace on OSX

Bug list:

Conclusions

The best platform for DTrace is OSX now.

DTrace on OSX more convenient than FreeBSD/Linux/Solaris because it has a modified toolchain. You need only use:

dtrace -h -s file.d -o header.h

And then include header.h in C code and compile binary file.

Thanks to

comments powered by Disqus