From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org,
boost.lists@gmail.com, quintela@redhat.com, jasowang@redhat.com,
mst@redhat.com, zuban32s@gmail.com,
maria.klimushenkova@ispras.ru, dovgaluk@ispras.ru,
kraxel@redhat.com, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com,
alex.bennee@linaro.org
Subject: [Qemu-devel] [RFC PATCH v3 27/30] scripts/replay-dump.py: replay log dumper
Date: Thu, 11 Jan 2018 11:27:27 +0300 [thread overview]
Message-ID: <20180111082727.27295.94934.stgit@pasha-VirtualBox> (raw)
In-Reply-To: <20180111082452.27295.85707.stgit@pasha-VirtualBox>
From: Alex Bennée <alex.bennee@linaro.org>
This script is a debugging tool for looking through the contents of a
replay log file. It is incomplete but should fail gracefully at events
it doesn't understand.
It currently understands two different log formats as the audio
record/replay support was merged during since MTTCG. It was written to
help debug what has caused the BQL changes to break replay support.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
v2
- yet another update to the log format
---
scripts/replay-dump.py | 308 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 308 insertions(+)
create mode 100755 scripts/replay-dump.py
diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py
new file mode 100755
index 0000000..203bb31
--- /dev/null
+++ b/scripts/replay-dump.py
@@ -0,0 +1,308 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Dump the contents of a recorded execution stream
+#
+# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+import argparse
+import struct
+from collections import namedtuple
+
+# This mirrors some of the global replay state which some of the
+# stream loading refers to. Some decoders may read the next event so
+# we need handle that case. Calling reuse_event will ensure the next
+# event is read from the cache rather than advancing the file.
+
+class ReplayState(object):
+ def __init__(self):
+ self.event = -1
+ self.event_count = 0
+ self.already_read = False
+ self.current_checkpoint = 0
+ self.checkpoint = 0
+
+ def set_event(self, ev):
+ self.event = ev
+ self.event_count += 1
+
+ def get_event(self):
+ self.already_read = False
+ return self.event
+
+ def reuse_event(self, ev):
+ self.event = ev
+ self.already_read = True
+
+ def set_checkpoint(self):
+ self.checkpoint = self.event - self.checkpoint_start
+
+ def get_checkpoint(self):
+ return self.checkpoint
+
+replay_state = ReplayState()
+
+# Simple read functions that mirror replay-internal.c
+# The file-stream is big-endian and manually written out a byte at a time.
+
+def read_byte(fin):
+ "Read a single byte"
+ return struct.unpack('>B', fin.read(1))[0]
+
+def read_event(fin):
+ "Read a single byte event, but save some state"
+ if replay_state.already_read:
+ return replay_state.get_event()
+ else:
+ replay_state.set_event(read_byte(fin))
+ return replay_state.event
+
+def read_word(fin):
+ "Read a 16 bit word"
+ return struct.unpack('>H', fin.read(2))[0]
+
+def read_dword(fin):
+ "Read a 32 bit word"
+ return struct.unpack('>I', fin.read(4))[0]
+
+def read_qword(fin):
+ "Read a 64 bit word"
+ return struct.unpack('>Q', fin.read(8))[0]
+
+# Generic decoder structure
+Decoder = namedtuple("Decoder", "eid name fn")
+
+def call_decode(table, index, dumpfile):
+ "Search decode table for next step"
+ decoder = next((d for d in table if d.eid == index), None)
+ if not decoder:
+ print "Could not decode index: %d" % (index)
+ print "Entry is: %s" % (decoder)
+ print "Decode Table is:\n%s" % (table)
+ return False
+ else:
+ return decoder.fn(decoder.eid, decoder.name, dumpfile)
+
+# Print event
+def print_event(eid, name, string=None, event_count=None):
+ "Print event with count"
+ if not event_count:
+ event_count = replay_state.event_count
+
+ if string:
+ print "%d:%s(%d) %s" % (event_count, name, eid, string)
+ else:
+ print "%d:%s(%d)" % (event_count, name, eid)
+
+
+# Decoders for each event type
+
+def decode_unimp(eid, name, _unused_dumpfile):
+ "Unimplimented decoder, will trigger exit"
+ print "%s not handled - will now stop" % (name)
+ return False
+
+# Checkpoint decoder
+def swallow_async_qword(eid, name, dumpfile):
+ "Swallow a qword of data without looking at it"
+ step_id = read_qword(dumpfile)
+ print " %s(%d) @ %d" % (name, eid, step_id)
+ return True
+
+async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
+ Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
+ Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
+ Decoder(3, "REPLAY_ASYNC_CHAR_READ", decode_unimp),
+ Decoder(4, "REPLAY_ASYNC_EVENT_BLOCK", decode_unimp),
+ Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
+]
+# See replay_read_events/replay_read_event
+def decode_async(eid, name, dumpfile):
+ """Decode an ASYNC event"""
+
+ print_event(eid, name)
+
+ async_event_kind = read_byte(dumpfile)
+ async_event_checkpoint = read_byte(dumpfile)
+
+ if async_event_checkpoint != replay_state.current_checkpoint:
+ print " mismatch between checkpoint %d and async data %d" % (
+ replay_state.current_checkpoint, async_event_checkpoint)
+ return True
+
+ return call_decode(async_decode_table, async_event_kind, dumpfile)
+
+
+def decode_instruction(eid, name, dumpfile):
+ ins_diff = read_dword(dumpfile)
+ print_event(eid, name, "0x%x" % (ins_diff))
+ return True
+
+def decode_audio_out(eid, name, dumpfile):
+ audio_data = read_dword(dumpfile)
+ print_event(eid, name, "%d" % (audio_data))
+ return True
+
+def decode_checkpoint(eid, name, dumpfile):
+ """Decode a checkpoint.
+
+ Checkpoints contain a series of async events with their own specific data.
+ """
+ replay_state.set_checkpoint()
+ # save event count as we peek ahead
+ event_number = replay_state.event_count
+ next_event = read_event(dumpfile)
+
+ # if the next event is EVENT_ASYNC there are a bunch of
+ # async events to read, otherwise we are done
+ if next_event != 3:
+ print_event(eid, name, "no additional data", event_number)
+ else:
+ print_event(eid, name, "more data follows", event_number)
+
+ replay_state.reuse_event(next_event)
+ return True
+
+def decode_checkpoint_init(eid, name, dumpfile):
+ print_event(eid, name)
+ return True
+
+def decode_interrupt(eid, name, dumpfile):
+ print_event(eid, name)
+ return True
+
+def decode_clock(eid, name, dumpfile):
+ clock_data = read_qword(dumpfile)
+ print_event(eid, name, "0x%x" % (clock_data))
+ return True
+
+
+# pre-MTTCG merge
+v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
+ Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
+ Decoder(2, "EVENT_EXCEPTION", decode_unimp),
+ Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
+ Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
+ Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
+ Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
+ Decoder(8, "EVENT_CLOCK_HOST", decode_clock),
+ Decoder(9, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
+ Decoder(10, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
+ Decoder(11, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
+ Decoder(12, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
+ Decoder(13, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
+ Decoder(14, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
+ Decoder(15, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
+ Decoder(16, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
+ Decoder(17, "EVENT_CP_INIT", decode_checkpoint_init),
+ Decoder(18, "EVENT_CP_RESET", decode_checkpoint),
+]
+
+# post-MTTCG merge, AUDIO support added
+v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
+ Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
+ Decoder(2, "EVENT_EXCEPTION", decode_unimp),
+ Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
+ Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
+ Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
+ Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
+ Decoder(8, "EVENT_AUDIO_OUT", decode_audio_out),
+ Decoder(9, "EVENT_AUDIO_IN", decode_unimp),
+ Decoder(10, "EVENT_CLOCK_HOST", decode_clock),
+ Decoder(11, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
+ Decoder(12, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
+ Decoder(13, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
+ Decoder(14, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
+ Decoder(15, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
+ Decoder(16, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
+ Decoder(17, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
+ Decoder(18, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
+ Decoder(19, "EVENT_CP_INIT", decode_checkpoint_init),
+ Decoder(20, "EVENT_CP_RESET", decode_checkpoint),
+]
+
+# Shutdown cause added
+v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
+ Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
+ Decoder(2, "EVENT_EXCEPTION", decode_unimp),
+ Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
+ Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
+ Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
+ Decoder(7, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
+ Decoder(8, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
+ Decoder(9, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
+ Decoder(10, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
+ Decoder(11, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
+ Decoder(12, "EVENT_SHUTDOWN___MAX", decode_unimp),
+ Decoder(13, "EVENT_CHAR_WRITE", decode_unimp),
+ Decoder(14, "EVENT_CHAR_READ_ALL", decode_unimp),
+ Decoder(15, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
+ Decoder(16, "EVENT_AUDIO_OUT", decode_audio_out),
+ Decoder(17, "EVENT_AUDIO_IN", decode_unimp),
+ Decoder(18, "EVENT_CLOCK_HOST", decode_clock),
+ Decoder(19, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
+ Decoder(20, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
+ Decoder(21, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
+ Decoder(22, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
+ Decoder(23, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
+ Decoder(24, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
+ Decoder(25, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
+ Decoder(26, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
+ Decoder(27, "EVENT_CP_INIT", decode_checkpoint_init),
+ Decoder(28, "EVENT_CP_RESET", decode_checkpoint),
+]
+
+def parse_arguments():
+ "Grab arguments for script"
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-f", "--file", help='record/replay dump to read from',
+ required=True)
+ return parser.parse_args()
+
+def decode_file(filename):
+ "Decode a record/replay dump"
+ dumpfile = open(filename, "rb")
+
+ # read and throwaway the header
+ version = read_dword(dumpfile)
+ junk = read_qword(dumpfile)
+
+ print "HEADER: version 0x%x" % (version)
+
+ if version == 0xe02007:
+ event_decode_table = v7_event_table
+ replay_state.checkpoint_start = 12
+ elif version == 0xe02006:
+ event_decode_table = v6_event_table
+ replay_state.checkpoint_start = 12
+ else:
+ event_decode_table = v5_event_table
+ replay_state.checkpoint_start = 10
+
+ try:
+ decode_ok = True
+ while decode_ok:
+ event = read_event(dumpfile)
+ decode_ok = call_decode(event_decode_table, event, dumpfile)
+ finally:
+ dumpfile.close()
+
+if __name__ == "__main__":
+ args = parse_arguments()
+ decode_file(args.file)
next prev parent reply other threads:[~2018-01-11 8:27 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-11 8:24 [Qemu-devel] [RFC PATCH v3 00/30] replay additions Pavel Dovgalyuk
2018-01-11 8:24 ` [Qemu-devel] [RFC PATCH v3 01/30] hpet: recover timer offset correctly Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 02/30] cpu: flush TB cache when loading VMState Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 03/30] This patch adds a condition before overwriting exception_index fields Pavel Dovgalyuk
2018-01-11 12:29 ` Paolo Bonzini
2018-01-12 6:12 ` Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 04/30] block: implement bdrv_snapshot_goto for blkreplay Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 05/30] blkreplay: create temporary overlay for underlaying devices Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 06/30] replay: disable default snapshot for record/replay Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 07/30] replay: fix processing async events Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 08/30] replay: fixed replay_enable_events Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 09/30] replay: fix save/load vm for non-empty queue Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 10/30] replay: added replay log format description Pavel Dovgalyuk
2018-01-11 8:25 ` [Qemu-devel] [RFC PATCH v3 11/30] replay: make safe vmstop at record/replay Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 12/30] replay: save prior value of the host clock Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 13/30] icount: fixed saving/restoring of icount warp timers Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 14/30] target/arm/arm-powertctl: drop BQL assertions Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 15/30] cpus: push BQL lock to qemu_*_wait_io_event Pavel Dovgalyuk
2018-01-11 12:50 ` Paolo Bonzini
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 16/30] cpus: only take BQL for sleeping threads Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 17/30] replay/replay.c: bump REPLAY_VERSION again Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 18/30] replay/replay-internal.c: track holding of replay_lock Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 19/30] replay: make locking visible outside replay code Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 20/30] replay: push replay_mutex_lock up the call tree Pavel Dovgalyuk
2018-01-11 8:26 ` [Qemu-devel] [RFC PATCH v3 21/30] replay: don't destroy mutex at exit Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 22/30] replay: check return values of fwrite Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 23/30] replay: avoid recursive call of checkpoints Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 24/30] scripts/qemu-gdb: add simple tcg lock status helper Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 25/30] util/qemu-thread-*: add qemu_lock, locked and unlock trace events Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 26/30] scripts/analyse-locks-simpletrace.py: script to analyse lock times Pavel Dovgalyuk
2018-01-11 8:27 ` Pavel Dovgalyuk [this message]
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 28/30] scripts/qemu-gdb/timers.py: new helper to dump timer state Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 29/30] replay: improve replay performance Pavel Dovgalyuk
2018-01-11 12:55 ` Paolo Bonzini
2018-01-11 13:12 ` Pavel Dovgalyuk
2018-01-11 13:22 ` Paolo Bonzini
2018-01-12 6:13 ` Pavel Dovgalyuk
2018-01-12 12:10 ` Paolo Bonzini
2018-01-12 12:41 ` Pavel Dovgalyuk
2018-01-11 8:27 ` [Qemu-devel] [RFC PATCH v3 30/30] replay: don't process async events when warping the clock Pavel Dovgalyuk
2018-01-11 12:37 ` Paolo Bonzini
2018-01-12 7:20 ` Pavel Dovgalyuk
2018-01-11 8:54 ` [Qemu-devel] [RFC PATCH v3 00/30] replay additions no-reply
2018-01-11 8:55 ` no-reply
2018-01-11 12:56 ` Paolo Bonzini
2018-01-12 9:32 ` Paolo Bonzini
2018-01-12 12:07 ` Pavel Dovgalyuk
2018-01-12 12:11 ` Paolo Bonzini
2018-01-19 6:35 ` Pavel Dovgalyuk
2018-01-19 7:41 ` Paolo Bonzini
2018-01-19 7:45 ` Pavel Dovgalyuk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180111082727.27295.94934.stgit@pasha-VirtualBox \
--to=pavel.dovgaluk@ispras.ru \
--cc=alex.bennee@linaro.org \
--cc=boost.lists@gmail.com \
--cc=dovgaluk@ispras.ru \
--cc=jasowang@redhat.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=maria.klimushenkova@ispras.ru \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=zuban32s@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.