Մի շաբաթ առաջ գրառեցի թէ ինչպէս DTrace-ով վօկին հետեւել, այսօր ուզում եմ խօսել թէ ինչպէս հետեւլ ծրագրերին առհասարակ։

Վերցնենք էս օրինակը Սի-ով՝

#include <unistd.h>
#include <stdlib.h>

void a();
void b();

void a() {
  sleep(1);
};

void b() {
  sleep(1);
};

int main() {
  while (1) {
    a();
    b();
  };
  exit(0);
}

Հիմա փորձենք հետեւլ DTrace-ով՝

root@illuria-dev:~/voc-dtrace # dtrace -F -n 'pid$target:prog0::entry,pid$target:prog0::return{} tick-5s{exit(0)}' -c ./prog0
dtrace: description 'pid$target:prog0::entry,pid$target:prog0::return' matched 17 probes
CPU FUNCTION
  0  -> _start
  0    -> handle_static_init
  0    <- handle_static_init
  0    -> main
  0      -> a
  0      <- a
  0      -> b
  0      <- b
  0      -> a
  1      <- a
  1      -> b
  1      <- b
  1      -> a
  0       | :tick-5s

Ահա փաստօրէն կարողանում ենք նաեւ տեսնել թէ ֆունկցիան երբ ա մտնում ու երբ ա դուրս գալիս։

Մի փոքր բացատրեմ, ունենք provider, module, function, probe, նշել եմ որ ուզում եմ օգտագործել pid provider-ը, որը հետեւում է userland-ում կատարուող գործերին, մոդուլը դրել եմ ծրագրի անունը՝ prog0, ֆունկցիան էական չի, իսկ probe-ը նշել եմ եւ entry (մուտք) եւ return (էլք)։ Նաեւ նշել եմ, որ 5 վայրկեան յետոյ դուրս գայ։

Օկ հրաշալի, հիմա փորձենք օբերոնով գրած ծրագիր՝

MODULE prog1;

IMPORT Platform;

PROCEDURE A();
BEGIN
  Platform.Delay(1000)
END A;

PROCEDURE B();
BEGIN
  Platform.Delay(1000)
END B;

BEGIN
  WHILE TRUE
  DO
    A();
    B();
  END
END prog1.

Հիմա փորձենք հետեւել DTrace-ով՝

root@illuria-dev:~/voc-dtrace # dtrace -F -n 'pid$target:prog1::entry,pid$target:prog1::return{} tick-5s{exit(0)}' -c ./prog1
dtrace: description 'pid$target:prog1::entry,pid$target:prog1::return' matched 17 probes
CPU FUNCTION
  1  -> _start
  1    -> handle_static_init
  1    <- handle_static_init
  1    -> main
  1      -> prog1_A
  1      <- prog1_A
  1      -> prog1_B
  1      <- prog1_B
  1      -> prog1_A
  1      <- prog1_A
  1      -> prog1_B
  1      <- prog1_B
  1      -> prog1_A
  0       | :tick-5s

Ահ, մի բան էն չի։ հմմ։ երեւի վօկի գեներացրած կոդից ա՝

/* voc 2.1.0 [2020/07/14] for clang LP64 on freebsd xtpam */

#define SHORTINT INT8
#define INTEGER  INT16
#define LONGINT  INT32
#define SET      UINT32

#include "SYSTEM.h"
#include "Platform.h"

static void prog1_A (void);
static void prog1_B (void);

static void prog1_A (void)
{
  Platform_Delay(1000);
}

static void prog1_B (void)
{
  Platform_Delay(1000);
}

export int main(int argc, char **argv)
{
  __INIT(argc, argv);
  __MODULE_IMPORT(Platform);
  __REGMAIN("prog1", 0);
/* BEGIN */
  while (1) {
    prog1_A();
    prog1_B();
  }
  __FINI;
}

Հա, փաստօրէն վօկի գեներացրած կոդից ա։

Լաւ, ենթադրենք սա իրական ծրագիր ա, ու ուզում ենք իմանալ ուր ա bottleneck-ը, պէտք է հասկանալ ամենաերկարը որտեղ ա ծրագրին երկար տեւում։

pid$target:prog1::entry
{
        self->ts = timestamp;
}

pid$target:prog1::return
/self->ts/
{
        @time[probefunc] = sum(timestamp - self->ts);
        self->ts = 0;
}

tick-5s
{
        exit(0)
}

Էս դէպքում ֆունկցիայի մէջ մտնելու ժամանակ ասում եմ որ ts փոփոխականի մէջ նշի timestamp-ը, ու ելքի ժամանակ ստուգել եթէ ts փոփոխականը յայտարարուած ա։

@time[probefunc] = sum(timestamp - self->ts); տողի վրայ ագրիգացիա է կատարւում գումարելով (sum) թէ ինչքան ժամանակ է տեւել մտնելուց մինչեւ դուրս գալը (timestamp - self->ts) ու պահում time փոփոխականի մէջ։

5 վայրկեան յետոյ դուրս է գալիս ։)

ահա՝

root@illuria-dev:~/voc-dtrace # dtrace -s prog1.d -c ./prog1
dtrace: script 'prog1.d' matched 17 probes
CPU     ID                    FUNCTION:NAME
  0  72544                         :tick-5s

  handle_static_init                                             5137
  prog1_A                                                  2057419770
  prog1_B                                                  2063438603

էսօրուայ համար էսքանը։

ասանկ բաներ։