From nobody Wed Nov 5 15:04:53 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=virtuozzo.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1535039472565860.6586193908693; Thu, 23 Aug 2018 08:51:12 -0700 (PDT) Received: from localhost ([::1]:37390 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsrt4-0007VB-MK for importer@patchew.org; Thu, 23 Aug 2018 11:51:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40822) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsrp9-0002jn-SX for qemu-devel@nongnu.org; Thu, 23 Aug 2018 11:47:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fsrp6-0007SU-Tf for qemu-devel@nongnu.org; Thu, 23 Aug 2018 11:47:03 -0400 Received: from relay.sw.ru ([185.231.240.75]:51386) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fsrp6-0007RE-J4; Thu, 23 Aug 2018 11:47:00 -0400 Received: from [10.28.8.145] (helo=kvm.sw.ru) by relay.sw.ru with esmtp (Exim 4.90_1) (envelope-from ) id 1fsrp3-0005sK-Ev; Thu, 23 Aug 2018 18:46:57 +0300 From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org, qemu-block@nongnu.org Date: Thu, 23 Aug 2018 18:46:54 +0300 Message-Id: <20180823154655.40188-3-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180823154655.40188-1-vsementsov@virtuozzo.com> References: <20180823154655.40188-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 185.231.240.75 Subject: [Qemu-devel] [PATCH v3 2/3] scripts: add render_block_graph function for QEMUMachine X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, famz@redhat.com, ehabkost@redhat.com, jsnow@redhat.com, armbru@redhat.com, mreitz@redhat.com, pbonzini@redhat.com, stefanha@redhat.com, crosa@redhat.com, den@openvz.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Render block nodes graph with help of graphviz. This new function is for debugging, so there is no sense to put it into qemu.py as a method of QEMUMachine. Let's instead put it separately. Signed-off-by: Vladimir Sementsov-Ogievskiy Acked-by: Eduardo Habkost Reviewed-by: Max Reitz --- scripts/render_block_graph.py | 120 ++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100755 scripts/render_block_graph.py diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py new file mode 100755 index 0000000000..382cc769ef --- /dev/null +++ b/scripts/render_block_graph.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# +# Render Qemu Block Graph +# +# Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import sys +import subprocess +import json +from graphviz import Digraph +from qemu import MonitorResponseError + + +def perm(arr): + s =3D 'w' if 'write' in arr else '_' + s +=3D 'r' if 'consistent-read' in arr else '_' + s +=3D 'u' if 'write-unchanged' in arr else '_' + s +=3D 'g' if 'graph-mod' in arr else '_' + s +=3D 's' if 'resize' in arr else '_' + return s + + +def render_block_graph(qmp, filename, format=3D'png'): + ''' + Render graph in text (dot) representation into "@filename" and + representation in @format into "@filename.@format" + ''' + + bds_nodes =3D qmp.command('query-named-block-nodes') + bds_nodes =3D {n['node-name']: n for n in bds_nodes} + + job_nodes =3D qmp.command('query-block-jobs') + job_nodes =3D {n['device']: n for n in job_nodes} + + block_graph =3D qmp.command('x-debug-query-block-graph') + + graph =3D Digraph(comment=3D'Block Nodes Graph') + graph.format =3D format + graph.node('permission symbols:\l' + ' w - Write\l' + ' r - consistent-Read\l' + ' u - write - Unchanged\l' + ' g - Graph-mod\l' + ' s - reSize\l' + 'edge label scheme:\l' + ' \l' + ' \l' + ' \l', shape=3D'none') + + for n in block_graph['nodes']: + if n['type'] =3D=3D 'bds': + info =3D bds_nodes[n['name']] + label =3D n['name'] + ' [' + info['drv'] + ']' + if info['drv'] =3D=3D 'file': + label +=3D '\n' + os.path.basename(info['file']) + shape =3D 'ellipse' + elif n['type'] =3D=3D 'job': + info =3D job_nodes[n['name']] + label =3D info['type'] + ' job (' + n['name'] + ')' + shape =3D 'box' + else: + assert n['type'] =3D=3D 'blk' + label =3D n['name'] if n['name'] else 'unnamed blk' + shape =3D 'box' + + graph.node(str(n['id']), label, shape=3Dshape) + + for e in block_graph['edges']: + label =3D '%s\l%s\l%s\l' % (e['name'], perm(e['perm']), + perm(e['shared-perm'])) + graph.edge(str(e['parent']), str(e['child']), label=3Dlabel) + + graph.render(filename) + + +class LibvirtGuest(): + def __init__(self, name): + self.name =3D name + + def command(self, cmd): + # only supports qmp commands without parameters + m =3D {'execute': cmd} + ar =3D ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)] + + reply =3D json.loads(subprocess.check_output(ar)) + + if 'error' in reply: + raise MonitorResponseError(reply) + + return reply['return'] + + +if __name__ =3D=3D '__main__': + obj =3D sys.argv[1] + out =3D sys.argv[2] + + if os.path.exists(obj): + # assume unix socket + qmp =3D QEMUMonitorProtocol(obj) + qmp.connect() + else: + # assume libvirt guest name + qmp =3D LibvirtGuest(obj) + + render_block_graph(qmp, out) --=20 2.18.0