Մի շաբաթ առաջ գրառեցի թէ ինչպէս 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
էսօրուայ համար էսքանը։
ասանկ բաներ։