Created
August 2, 2020 13:49
-
-
Save zhuizhuhaomeng/feefbbff6c6f4cc69fd1d43fa399c38e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/opsrun | |
use xray-cli; | |
use xray-agent-lib; | |
my Int $MAX-ITERS = 3; | |
my Str (@iterators, @results); | |
my Bool $finished; | |
my Int %mem{Str} = ( | |
'http_luajit_allocator': 0, | |
'stream_luajit_allocator': 0, | |
'glibc_arena': 0, | |
'glibc_mmaped': 0, | |
'jemalloc_mmaped': 0, | |
'nginx_shm_loaded': 0, | |
'musl_libc_heap': 0, | |
); | |
my Int (%total-zones{Str}, %loaded-zones{Str}); | |
my Str %addr-zones{Str}; | |
my Int %loaded-unknow-map-files{Str}; | |
my Int (%total-mmaps{Str}, %loaded-mmaps{Str}); | |
my Int $sum-loaded-mmaps = 0; | |
my Str $tool = 'resty-memory'; | |
my Str @base-opts; | |
my Int $len; | |
my Str $iter; | |
my Int $runs = 0; | |
my Str $data-file; | |
action check-shm-loaded (Int $pid) ret Int | |
{ | |
my Int $sum-loaded = 0; | |
my Str (@map-files, @range-starts, %shm-start-to-end{Str}); | |
my Str (%name-to-range{Str}, %range-to-zones{Str}); | |
my Int $size; | |
my Str $zone; | |
my Str $range; | |
my Int ($loaded-page, $total-page); | |
my Int $pagesize = 4096; | |
$ getconf PAGE_SIZE, | |
{ | |
failed => | |
say("can't get page size by 'getconf PAGE_SIZE', use default value $pagesize"), | |
nop; | |
true => | |
$pagesize = cout; | |
}, | |
$ awk '$2 == "rw-s" && $6 == "/dev/zero" && $7 == "(deleted)"{print $1}' /proc/$.pid/maps, | |
stream { | |
out contains rx{^([a-f0-9]+)\-([a-f0-9]+)\n} => | |
push(@range-starts, $1), | |
%shm-start-to-end{$1} = $2, | |
redo(tries: 1024); | |
found-prompt => break; | |
}, | |
# range-starts is already sorted and with 12 chars. | |
lua { | |
local zones = %addr-zones | |
local starts = @range-starts | |
local map_files = @map-files | |
local start_to_end = %shm-start-to-end | |
local range_to_zones = %range-to-zones | |
local n = 0 | |
for addr, zone in pairs(zones) do | |
local range | |
for i = 0, starts.len - 1 do | |
local start = starts[starts.base + i] | |
if addr >= start and addr < start_to_end[start] then | |
range = start .. "-" .. start_to_end[start] | |
break | |
end | |
end | |
if range then | |
range_to_zones[range] = zone | |
end | |
end | |
for i = 0, starts.len - 1 do | |
local start = starts[starts.base + i] | |
local range = start .. "-" .. start_to_end[start] | |
table.insert(map_files, "/proc/" .. $pid .. "/map_files/" .. range) | |
end | |
map_files.base = 1 | |
map_files.len = starts.len | |
}, | |
{ | |
@map-files => | |
$ mincore @.map-files, | |
stream { | |
out contains rx{^([a-f0-9]+\-[a-f0-9]+): (\d+)\/(\d+) pages present} => | |
$range = $1, | |
$loaded-page = to-int($2), | |
$total-page = to-int($3), | |
$zone = %range-to-zones{$range}, | |
{ | |
defined($zone) => | |
$size = %total-zones{$zone} / $total-page * $loaded-page, | |
%loaded-zones{$zone} = $size, | |
$sum-loaded += $size, | |
{ | |
$loaded-page > 0 => | |
# TODO: get pagesize in another way. | |
$pagesize = $size / $loaded-page; | |
}, | |
done; | |
true => | |
$size = $loaded-page * $pagesize, | |
%loaded-mmaps{$range} = $size, | |
%total-mmaps{$range} = $total-page * $pagesize, | |
$sum-loaded-mmaps += $size; | |
}, | |
redo(tries: 1024); | |
found-prompt => break; | |
}, | |
done; | |
}, | |
return $sum-loaded; | |
} | |
action merge-result () { | |
my Str $data-file; | |
shift(@iterators), | |
$data-file = shift(@results), | |
{ | |
!defined($data-file); $data-file eq "" => | |
done; | |
true => | |
$ cat "$.data-file", | |
stream { | |
out contains /^http luajit GC managed: (\d+)\n/ => | |
%mem<http_luajit_GC_managed> = to-int($1); | |
out contains /^http luajit allocator: (\d+)\n/ => | |
%mem<http_luajit_allocator> += to-int($1); | |
out contains /^stream luajit GC managed: (\d+)\n/ => | |
%mem<stream_luajit_GC_managed> = to-int($1); | |
out contains /^stream luajit allocator: (\d+)\n/ => | |
%mem<stream_luajit_allocator> += to-int($1); | |
out contains /^musl libc heap: (\d+)\n/ => | |
%mem<musl_libc_heap> += to-int($1); | |
out contains /^glibc arena: (\d+)\n/ => | |
%mem<glibc_arena> += to-int($1); | |
out contains /^glibc mmaped: (\d+)\n/ => | |
%mem<glibc_mmaped> += to-int($1); | |
out contains /^jemalloc mmaped: (\d+)\n/ => | |
%mem<jemalloc_mmaped> += to-int($1); | |
out contains /^shm zone (.*?): total=(\d+) addr=0x(\w+)\n/ => | |
%total-zones{$1} = to-int($2), | |
%loaded-zones{$1} = 0, | |
%addr-zones{$3} = $1, | |
redo(tries: 1024); | |
found-prompt => break; | |
}; | |
}, | |
nop; | |
} | |
action finish-iterator (Int $pid) { | |
again: | |
{ | |
elems(@iterators) == 0 => | |
done; | |
true => | |
merge-result, | |
goto(again, tries: $MAX-ITERS + 2); | |
}, | |
%mem<nginx_shm_loaded> = check-shm-loaded($pid), | |
%mem<mmap_loaded> = $sum-loaded-mmaps, | |
$ cat /proc/$.pid/status | grep Vm, | |
stream { | |
out contains /VmExe:\s+(\d+)\s+kB/ => | |
%mem<vm_exe> = to-int($1) * 1024; | |
out contains /VmLib:\s+(\d+)\s+kB/ => | |
%mem<vm_lib> = to-int($1) * 1024; | |
out contains /VmStk:\s+(\d+)\s+kB/ => | |
%mem<vm_stack> = to-int($1) * 1024; | |
found-prompt => break; | |
}, | |
say("JS: json: resty-memory: ", '{"summary": ', encode-json(%mem), | |
',"total-shms":', encode-json(%total-zones), | |
',"loaded-shms":', encode-json(%loaded-zones), | |
',"total-mmaps":', encode-json(%total-mmaps), | |
',"loaded-mmaps":', encode-json(%loaded-mmaps), | |
'}' | |
), | |
exit(0); | |
} | |
goal all (Str $cwd, Str $ko-file, Int $pid) { | |
run { | |
$ cd $.cwd, | |
init-target-box, | |
@base-opts = gen-staprun-opts($pid), | |
say("info: running tool $tool ..."), | |
$runs++, | |
$data-file = "data.$runs", | |
run-staprun-simple($ko-file, @base-opts, nil, $data-file), | |
{ | |
failed => | |
check-readfault(cout), | |
die("failed to run tool: ", cout); | |
}, | |
init-iterator(@iterators, @results, $MAX-ITERS - 1), | |
again: | |
$finished = push-iterator(@iterators, @results, cout, $data-file), | |
$len = elems(@iterators), | |
{ | |
$finished => | |
finish-iterator($pid), | |
done; | |
$len == 0 => | |
# too much rollback | |
die("failed to continue from the previous run: ", cout); | |
$len > $MAX-ITERS => | |
merge-result, | |
$len = elems(@iterators); | |
}, | |
$iter = @iterators[$len - 1], | |
$runs++, | |
$data-file = "data.$runs", | |
run-staprun-simple($ko-file, @base-opts, $iter, $data-file), | |
{ | |
failed => | |
check-readfault(cout, true), | |
rollback-iterator(@iterators, @results); | |
true => | |
goto(again, tries: 200); | |
}, | |
nop; | |
} | |
} | |
goal all-odb (Str $cwd, Str $ko-file, Int $pid) { | |
run { | |
$ cd $.cwd, | |
init-target-box, | |
@base-opts = gen-odb-opts($pid), | |
say("info: running tool $tool by odb ..."), | |
$runs++, | |
$data-file = "data.$runs", | |
$ chmod +x $.ko-file, | |
run-odb-simple($ko-file, @base-opts, nil, $data-file), | |
{ | |
failed => | |
die("failed to run tool: ", cout); | |
}, | |
init-iterator(@iterators, @results, $MAX-ITERS - 1), | |
again: | |
$finished = push-iterator(@iterators, @results, cout, $data-file), | |
$len = elems(@iterators), | |
{ | |
$finished => | |
finish-iterator($pid), | |
done; | |
$len == 0 => | |
# too much rollback | |
die("failed to continue from the previous run: ", cout); | |
$len > $MAX-ITERS => | |
merge-result, | |
$len = elems(@iterators); | |
}, | |
$iter = @iterators[$len - 1], | |
$runs++, | |
$data-file = "data.$runs", | |
run-odb-simple($ko-file, @base-opts, $iter, $data-file), | |
{ | |
failed => | |
rollback-iterator(@iterators, @results); | |
true => | |
goto(again, tries: 1000); | |
}, | |
nop; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment