Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/scripts/install-drgn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# These are build requirements of "drgn"; if we don't install these, the
# build/install of "drgn" will fail below.
#
sudo apt-get install bison flex libelf-dev libdw-dev libomp5 libomp-dev
sudo apt update
sudo apt install bison flex libelf-dev libdw-dev libomp5 libomp-dev

git clone https://github.com/osandov/drgn.git

Expand Down
5 changes: 3 additions & 2 deletions .github/scripts/install-libkdumpfile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
# all version of python3.X-dev so the Github actions jobs can install
# libkdumpfile with the right version.
#
sudo apt-get install autoconf automake liblzo2-dev libsnappy1v5 libtool pkg-config zlib1g-dev
sudo apt-get install python3.6-dev python3.7-dev python3.8-dev
sudo apt update
sudo apt install autoconf automake liblzo2-dev libsnappy1v5 libtool pkg-config zlib1g-dev
sudo apt install python3.6-dev python3.7-dev python3.8-dev

git clone https://github.com/ptesarik/libkdumpfile.git

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ The Slick/Simple Debugger

Ensure you have the following dependencies:
* Python 3.6 or newer
* [libkdumpfile](https://github.com/ptesarik/libkdumpfile) (optional - needed for kdump-compressed crash dumps)
* [drgn](https://github.com/osandov/drgn/)

Then run:
Note that in order for `drgn` to support kdump files it needs to be *compiled* with `libkdumpfile`. Unfortunately that means that users should always install `libkdumpfile` first before installing `drgn`.

Finally run the following to install `sdb`:
```
$ git clone https://github.com/delphix/sdb.git
$ cd sdb
$ sudo python3 setup.py install
```

The above should install `sdb` under `/usr/local/bin/`.

### Resources

User and developer resources for sdb can be found in the [project's wiki](https://github.com/delphix/sdb/wiki).
8 changes: 4 additions & 4 deletions sdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
CommandInvalidInputError, SymbolNotFoundError,
CommandArgumentsError, CommandEvalSyntaxError,
ParserError)
from sdb.target import (create_object, get_object, get_prog, get_typed_null,
get_type, get_pointer_type, get_target_flags,
get_symbol, type_canonical_name, type_canonicalize,
from sdb.target import (create_object, get_object, get_prog, get_type,
get_pointer_type, get_target_flags, get_symbol, is_null,
type_canonical_name, type_canonicalize,
type_canonicalize_name, type_canonicalize_size,
type_equals)
from sdb.command import (Address, Cast, Command, InputHandler, Locator,
Expand Down Expand Up @@ -63,6 +63,7 @@
'create_object',
'execute_pipeline',
'invoke',
'is_null',
'get_first_type',
'get_object',
'get_pointer_type',
Expand All @@ -71,7 +72,6 @@
'get_symbol',
'get_target_flags',
'get_type',
'get_typed_null',
'type_canonical_name',
'type_canonicalize',
'type_canonicalize_name',
Expand Down
2 changes: 1 addition & 1 deletion sdb/commands/spl/avl.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Avl(sdb.Walker):
input_type = "avl_tree_t *"

def _helper(self, node: drgn.Object, offset: int) -> Iterable[drgn.Object]:
if node == sdb.get_typed_null(node.type_):
if sdb.is_null(node):
return

lchild = node.avl_child[0]
Expand Down
4 changes: 2 additions & 2 deletions sdb/commands/zfs/dbuf.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ def ObjsetName(os: drgn.Object) -> str:
os.os_spa.spa_name.string_().decode("utf-8"))
return Dbuf.DatasetName(os.os_dsl_dataset)

def pretty_print(self, dbufs: drgn.Object) -> None:
def pretty_print(self, objs: drgn.Object) -> None:
print("{:>20} {:>8} {:>4} {:>8} {:>5} {}".format(
"addr", "object", "lvl", "blkid", "holds", "os"))
for dbuf in filter(self.argfilter, dbufs):
for dbuf in filter(self.argfilter, objs):
print("{:>20} {:>8d} {:>4d} {:>8d} {:>5d} {}".format(
hex(dbuf), int(dbuf.db.db_object), int(dbuf.db_level),
int(dbuf.db_blkid), int(dbuf.db_holds.rc_count),
Expand Down
17 changes: 9 additions & 8 deletions sdb/commands/zfs/histograms.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def histogram_median(hist: drgn.Object, offset: int = 0) -> int:
for (bucket, value) in enumerate(hist):
space_in_bucket = int(value) << (bucket + offset)
if space_left <= space_in_bucket:
median = 1 << (bucket + offset)
median = 1 << (bucket + offset - 1)
#
# Size of segments may vary within one bucket thus we
# attempt to approximate the median by looking at the
Expand Down Expand Up @@ -136,19 +136,20 @@ def print_histogram(hist: drgn.Object,
if max_count < HISTOGRAM_WIDTH_MAX:
max_count = HISTOGRAM_WIDTH_MAX

if min_bucket <= max_bucket:
print(f'{" " * indent}seg-size count')
print(f'{" " * indent}{"-" * 8} {"-" * 5}')
if min_bucket > max_bucket:
print(f'{" " * indent}** No histogram data available **')
return

print(f'{" " * indent}seg-size count')
print(f'{" " * indent}{"-" * 8} {"-" * 5}')

for bucket in range(min_bucket, max_bucket + 1):
count = int(hist[bucket])
stars = round(count * HISTOGRAM_WIDTH_MAX / max_count)
print(f'{" " * indent}{fmt.size_nicenum(2**(bucket+offset)):>8}: '
f'{count:>6} {"*" * stars}')
if min_bucket > max_bucket:
print(f'{" " * indent}** No histogram data available **')
else:
ZFSHistogram.print_histogram_median(hist, offset, indent)

ZFSHistogram.print_histogram_median(hist, offset, indent)

def _call(self, objs: Iterable[drgn.Object]) -> None:
for obj in objs:
Expand Down
13 changes: 8 additions & 5 deletions sdb/commands/zfs/metaslab.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def print_metaslab(msp: drgn.Object, print_header: bool,
print("".ljust(indent), "-" * 65)

free = msp.ms_size
if spacemap != sdb.get_typed_null(spacemap.type_):
if not sdb.is_null(spacemap):
free -= spacemap.sm_phys.smp_alloc

ufrees = msp.ms_unflushed_frees.rt_space
Expand All @@ -160,16 +160,16 @@ def print_metaslab(msp: drgn.Object, print_header: bool,
print((str(int(msp.ms_fragmentation)) + "%").rjust(6), end="")
print(nicenum(uchanges_mem).rjust(9))

def pretty_print(self,
metaslabs: Iterable[drgn.Object],
indent: int = 0) -> None:
def print_indented(self,
metaslabs: Iterable[drgn.Object],
indent: int = 0) -> None:
first_time = True
for msp in metaslabs:
if not self.args.weight:
Metaslab.print_metaslab(msp, first_time, indent)
if self.args.histogram:
spacemap = msp.ms_sm
if spacemap != sdb.get_typed_null(spacemap.type_):
if not sdb.is_null(spacemap):
histogram = spacemap.sm_phys.smp_histogram
ZFSHistogram.print_histogram(histogram,
int(spacemap.sm_shift),
Expand All @@ -178,6 +178,9 @@ def pretty_print(self,
Metaslab.metaslab_weight_print(msp, first_time, indent)
first_time = False

def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
self.print_indented(objs, 0)

@sdb.InputHandler("vdev_t*")
def from_vdev(self, vdev: drgn.Object) -> Iterable[drgn.Object]:
if self.args.metaslab_ids:
Expand Down
6 changes: 3 additions & 3 deletions sdb/commands/zfs/spa.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ def __init__(self,
if self.args.weight:
self.arg_list.append("-w")

def pretty_print(self, spas: Iterable[drgn.Object]) -> None:
def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
print("{:18} {}".format("ADDR", "NAME"))
print("%s" % ("-" * 60))
for spa in spas:
for spa in objs:
print("{:18} {}".format(hex(spa),
spa.spa_name.string_().decode("utf-8")))
if self.args.histogram:
Expand All @@ -77,7 +77,7 @@ def pretty_print(self, spas: Iterable[drgn.Object]) -> None:

if self.args.vdevs or self.args.metaslab:
vdevs = sdb.execute_pipeline([spa], [Vdev()])
Vdev(self.arg_list).pretty_print(vdevs, 5)
Vdev(self.arg_list).print_indented(vdevs, 5)

def no_input(self) -> drgn.Object:
spas = sdb.execute_pipeline(
Expand Down
45 changes: 11 additions & 34 deletions sdb/commands/zfs/vdev.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# pylint: disable=missing-docstring

import argparse
from typing import Iterable, List, Tuple, Optional
from typing import Iterable, List, Optional

import drgn
import sdb
Expand Down Expand Up @@ -69,34 +69,9 @@ def __init__(self,
if self.args.weight:
self.arg_list.append("-w")

#
# Iterate over the metaslabs to accumulate histogram data.
#
@staticmethod
def sum_histograms(
metaslabs: Iterable[drgn.Object]) -> Tuple[drgn.Object, int]:
shift = -1
length = 1
first_time = True
histsum: List[int] = []
for msp in metaslabs:
if msp.ms_sm == sdb.get_typed_null(msp.ms_sm.type_):
continue
histogram = msp.ms_sm.sm_phys.smp_histogram
if first_time:
shift = int(msp.ms_sm.sm_shift)
length = len(histogram)
histsum = [0] * length
assert length == len(histogram)
assert shift == int(msp.ms_sm.sm_shift)
for (bucket, value) in enumerate(histogram):
histsum[bucket] += int(value)
first_time = False
return sdb.create_object(f'uint64_t[{length}]', histsum), shift

def pretty_print(self,
vdevs: Iterable[drgn.Object],
indent: int = 0) -> None:
def print_indented(self,
vdevs: Iterable[drgn.Object],
indent: int = 0) -> None:
print(
"".ljust(indent),
"ADDR".ljust(18),
Expand Down Expand Up @@ -133,14 +108,16 @@ def pretty_print(self,
vdev.vdev_ops.vdev_op_type.string_().decode("utf-8"),
)
if self.args.histogram:
metaslabs = sdb.execute_pipeline([vdev], [Metaslab()])
histsum, shift = self.sum_histograms(metaslabs)
if shift > 0:
ZFSHistogram.print_histogram(histsum, shift, indent + 5)
if not sdb.is_null(vdev.vdev_mg):
ZFSHistogram.print_histogram(vdev.vdev_mg.mg_histogram, 0,
indent + 5)

if self.args.metaslab:
metaslabs = sdb.execute_pipeline([vdev], [Metaslab()])
Metaslab(self.arg_list).pretty_print(metaslabs, indent + 5)
Metaslab(self.arg_list).print_indented(metaslabs, indent + 5)

def pretty_print(self, objs: Iterable[drgn.Object]) -> None:
self.print_indented(objs, 0)

@sdb.InputHandler("spa_t*")
def from_spa(self, spa: drgn.Object) -> Iterable[drgn.Object]:
Expand Down
4 changes: 2 additions & 2 deletions sdb/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ def get_pointer_type(type_name: str) -> drgn.Type:
return prog.pointer_type(type_name)


def get_typed_null(type_name: str) -> drgn.Object:
def is_null(obj: drgn.Object) -> bool:
global prog
return drgn.NULL(prog, type_name)
return bool(obj == drgn.NULL(prog, obj.type_))


def create_object(type_: Union[str, drgn.Type], val: Any) -> drgn.Object:
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/data/regression_output/zfs/spa -H
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ADDR NAME
64.0MB: 0
128.0MB: 0
256.0MB: 15 ***************
Approx. Median: 384.0MB
Approx. Median: 192.0MB
0xffffa089413b8000 meta-domain
seg-size count
-------- -----
Expand All @@ -45,6 +45,6 @@ ADDR NAME
32.0MB: 0
64.0MB: 1 *
128.0MB: 4 ****
Approx. Median: 184.0MB
Approx. Median: 92.0MB
0xffffa08955c44000 rpool
** No histogram data available **
Loading