mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
contrib: Visualizing block device access and alignment.
This commit is contained in:
2
contrib/visualize-alignment/.gitignore
vendored
Normal file
2
contrib/visualize-alignment/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.eps
|
||||
*.png
|
||||
19
contrib/visualize-alignment/README
Normal file
19
contrib/visualize-alignment/README
Normal file
@@ -0,0 +1,19 @@
|
||||
- guestfish-N-fs-10M.qtr
|
||||
|
||||
The command 'guestfish -N fs:ext2:10' before we modified the
|
||||
part-disk API to align the partition to 64 sectors.
|
||||
|
||||
- guestfish-N-fs-10M-aligned-part-disk.qtr
|
||||
|
||||
The command 'guestfish -N fs:ext2:10' after we modified the
|
||||
part-disk API to align the partition to 64 sectors.
|
||||
|
||||
- guestfish-add-mount.qtr
|
||||
|
||||
$ guestfish -a test1.img -m /dev/sda1
|
||||
where test1.img was created by the previous command.
|
||||
|
||||
- guestfish-write-hello.qtr
|
||||
|
||||
$ guestfish -a test1.img -m /dev/sda1 write /hello "hello, world."
|
||||
Note that the trace includes the adding and mounting operations.
|
||||
@@ -0,0 +1,122 @@
|
||||
S 20480
|
||||
R 0 1
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 0 32
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 0 8
|
||||
R 0 8
|
||||
R 0 32
|
||||
R 32 64
|
||||
R 128 8
|
||||
R 20456 8
|
||||
W 0 24
|
||||
W 20456 24
|
||||
R 0 8
|
||||
R 8 24
|
||||
W 0 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 32
|
||||
R 32 64
|
||||
W 0 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20472 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 20464 8
|
||||
R 8 8
|
||||
R 0 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 8
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 0 8
|
||||
R 64 2
|
||||
W 64 379
|
||||
W 443 55
|
||||
W 16450 4
|
||||
W 16532 92
|
||||
R 20416 1
|
||||
R 20160 1
|
||||
R 20161 1
|
||||
R 20162 1
|
||||
R 20163 5
|
||||
R 2112 1
|
||||
R 2113 1
|
||||
R 2114 6
|
||||
R 576 1
|
||||
R 577 1
|
||||
R 578 6
|
||||
R 4160 1
|
||||
R 4161 1
|
||||
R 4162 6
|
||||
R 0 8
|
||||
W 16624 230
|
||||
W 20288 128
|
||||
W 66 2
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 8
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 0 8
|
||||
122
contrib/visualize-alignment/guestfish-N-fs-10M.qtr
Normal file
122
contrib/visualize-alignment/guestfish-N-fs-10M.qtr
Normal file
@@ -0,0 +1,122 @@
|
||||
S 20480
|
||||
R 0 1
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 0 32
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 0 8
|
||||
R 0 8
|
||||
R 0 32
|
||||
R 32 64
|
||||
R 128 8
|
||||
R 20456 8
|
||||
W 0 24
|
||||
W 20456 24
|
||||
R 0 8
|
||||
R 8 24
|
||||
W 0 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 32
|
||||
R 32 64
|
||||
W 0 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 20464 8
|
||||
R 8 8
|
||||
R 0 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 20225 8
|
||||
R 20457 8
|
||||
R 1 8
|
||||
R 9 8
|
||||
R 20473 7
|
||||
R 20217 8
|
||||
R 20465 8
|
||||
R 2049 8
|
||||
R 25 8
|
||||
R 57 8
|
||||
R 121 8
|
||||
R 17 8
|
||||
R 129 8
|
||||
R 65 8
|
||||
R 513 8
|
||||
R 33 8
|
||||
R 4097 8
|
||||
R 0 8
|
||||
R 1 2
|
||||
R 20225 8
|
||||
W 1 436
|
||||
W 16387 1
|
||||
W 16388 3
|
||||
W 16469 324
|
||||
W 20225 248
|
||||
R 20473 7
|
||||
R 20217 8
|
||||
R 2049 1
|
||||
R 2050 1
|
||||
R 2051 6
|
||||
R 513 1
|
||||
R 514 1
|
||||
R 515 1
|
||||
R 516 1
|
||||
R 517 1
|
||||
R 518 1
|
||||
R 519 1
|
||||
R 520 1
|
||||
R 4097 1
|
||||
R 4098 7
|
||||
R 0 8
|
||||
W 3 2
|
||||
R 20225 8
|
||||
R 20457 8
|
||||
R 1 8
|
||||
R 9 8
|
||||
R 20473 7
|
||||
R 20217 8
|
||||
R 20465 8
|
||||
R 2049 8
|
||||
R 25 8
|
||||
R 57 8
|
||||
R 121 8
|
||||
R 17 8
|
||||
R 129 8
|
||||
R 65 8
|
||||
R 513 8
|
||||
R 33 8
|
||||
R 4097 8
|
||||
R 0 8
|
||||
72
contrib/visualize-alignment/guestfish-add-mount.qtr
Normal file
72
contrib/visualize-alignment/guestfish-add-mount.qtr
Normal file
@@ -0,0 +1,72 @@
|
||||
S 20480
|
||||
R 0 1
|
||||
R 0 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 8
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 0 8
|
||||
R 0 32
|
||||
R 20288 1
|
||||
R 20400 1
|
||||
R 64 1
|
||||
R 72 1
|
||||
R 64 4
|
||||
R 64 4
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 8
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 66 2
|
||||
R 68 2
|
||||
R 152 2
|
||||
W 66 2
|
||||
W 66 2
|
||||
W 66 2
|
||||
W 66 2
|
||||
W 66 2
|
||||
81
contrib/visualize-alignment/guestfish-write-hello.qtr
Normal file
81
contrib/visualize-alignment/guestfish-write-hello.qtr
Normal file
@@ -0,0 +1,81 @@
|
||||
S 20480
|
||||
R 0 1
|
||||
R 0 8
|
||||
R 20352 8
|
||||
R 20464 8
|
||||
R 0 8
|
||||
R 8 8
|
||||
R 20472 8
|
||||
R 20216 8
|
||||
R 20416 8
|
||||
R 20224 8
|
||||
R 20080 8
|
||||
R 2048 8
|
||||
R 24 8
|
||||
R 56 8
|
||||
R 120 8
|
||||
R 16 8
|
||||
R 128 8
|
||||
R 64 8
|
||||
R 512 8
|
||||
R 32 8
|
||||
R 4096 8
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 1
|
||||
R 20161 7
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 0 8
|
||||
R 0 32
|
||||
R 20288 1
|
||||
R 20400 1
|
||||
R 64 1
|
||||
R 72 1
|
||||
R 64 4
|
||||
R 64 4
|
||||
R 20288 8
|
||||
R 20400 8
|
||||
R 64 8
|
||||
R 72 8
|
||||
R 20416 1
|
||||
R 20160 8
|
||||
R 20408 8
|
||||
R 2112 8
|
||||
R 88 8
|
||||
R 120 8
|
||||
R 184 8
|
||||
R 80 8
|
||||
R 192 8
|
||||
R 128 8
|
||||
R 576 8
|
||||
R 96 8
|
||||
R 4160 8
|
||||
R 66 2
|
||||
R 68 2
|
||||
R 152 2
|
||||
W 66 2
|
||||
R 470 2
|
||||
R 150 2
|
||||
R 154 2
|
||||
R 148 2
|
||||
W 66 4
|
||||
W 148 2
|
||||
W 470 2
|
||||
W 13378 2
|
||||
W 150 6
|
||||
W 66 2
|
||||
W 66 2
|
||||
W 66 2
|
||||
@@ -0,0 +1,104 @@
|
||||
From e04ef476fd330485e5a88c7018d29c55cf411fe2 Mon Sep 17 00:00:00 2001
|
||||
From: Richard W.M. Jones <rjones@redhat.com>
|
||||
Date: Tue, 5 Oct 2010 09:54:10 +0100
|
||||
Subject: [PATCH] Trace reads and writes to qemu block devices.
|
||||
|
||||
NB: This patch is not suitable for nor intended to go upstream in
|
||||
its current form.
|
||||
|
||||
When qemu opens a block device, this patch creates a trace file
|
||||
in /tmp with a name related to the block device. Reads and writes
|
||||
to the device cause lines to be written to the trace file:
|
||||
|
||||
S <total_sectors>
|
||||
W <sector> <nb_sectors>
|
||||
R <sector> <nb_sectors>
|
||||
|
||||
'S' is the summary line, printed first which just tells you how
|
||||
many sectors are on the device.
|
||||
|
||||
'W' and 'R' are writes and reads, for the range <sector> through
|
||||
to <sector> + <nb_sectors> - 1.
|
||||
---
|
||||
block.c | 29 +++++++++++++++++++++++++++++
|
||||
block_int.h | 3 +++
|
||||
2 files changed, 32 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/block.c b/block.c
|
||||
index ebbc376..26ead5b 100644
|
||||
--- a/block.c
|
||||
+++ b/block.c
|
||||
@@ -474,6 +474,23 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
+ /* Open trace file in /tmp based on filename. XXX */
|
||||
+ size_t len = strlen (filename);
|
||||
+ char *trace_file = qemu_malloc (10 + len);
|
||||
+ snprintf (trace_file, 10 + len, "/tmp/%s.qtr", filename);
|
||||
+ size_t i;
|
||||
+ for (i = 5; i < 5 + len; ++i) {
|
||||
+ if (trace_file[i] == '/')
|
||||
+ trace_file[i] = '_';
|
||||
+ }
|
||||
+ bs->trace_fp = fopen (trace_file, "w");
|
||||
+ if (bs->trace_fp) {
|
||||
+ setlinebuf (bs->trace_fp);
|
||||
+ fprintf (bs->trace_fp, "S %" PRIi64 "\n", bs->total_sectors);
|
||||
+ } else {
|
||||
+ perror (trace_file);
|
||||
+ }
|
||||
+
|
||||
#ifndef _WIN32
|
||||
if (bs->is_temporary) {
|
||||
unlink(filename);
|
||||
@@ -665,6 +682,10 @@ void bdrv_close(BlockDriverState *bs)
|
||||
bdrv_close(bs->file);
|
||||
}
|
||||
|
||||
+ if (bs->trace_fp)
|
||||
+ fclose (bs->trace_fp);
|
||||
+ bs->trace_fp = NULL;
|
||||
+
|
||||
/* call the change callback */
|
||||
bs->media_changed = 1;
|
||||
if (bs->change_cb)
|
||||
@@ -1995,6 +2016,10 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
/* Update stats even though technically transfer has not happened. */
|
||||
bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
|
||||
bs->rd_ops ++;
|
||||
+
|
||||
+ if (bs->trace_fp)
|
||||
+ fprintf (bs->trace_fp,
|
||||
+ "R %" PRIi64 " %d\n", sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -2028,6 +2053,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
|
||||
bs->wr_highest_sector = sector_num + nb_sectors - 1;
|
||||
}
|
||||
+
|
||||
+ if (bs->trace_fp)
|
||||
+ fprintf (bs->trace_fp,
|
||||
+ "W %" PRIi64 " %d\n", sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
return ret;
|
||||
diff --git a/block_int.h b/block_int.h
|
||||
index e8e7156..03e7c9b 100644
|
||||
--- a/block_int.h
|
||||
+++ b/block_int.h
|
||||
@@ -178,6 +178,9 @@ struct BlockDriverState {
|
||||
uint64_t wr_ops;
|
||||
uint64_t wr_highest_sector;
|
||||
|
||||
+ /* Trace to file. */
|
||||
+ FILE *trace_fp;
|
||||
+
|
||||
/* Whether the disk can expand beyond total_sectors */
|
||||
int growable;
|
||||
|
||||
--
|
||||
1.7.3.1
|
||||
|
||||
354
contrib/visualize-alignment/tracetops.ml
Executable file
354
contrib/visualize-alignment/tracetops.ml
Executable file
@@ -0,0 +1,354 @@
|
||||
#!/usr/bin/ocamlrun /usr/bin/ocaml
|
||||
|
||||
#use "topfind";;
|
||||
#require "extlib";;
|
||||
|
||||
(* Convert *.qtr (qemu block device trace) to Postscript. By Richard
|
||||
* W.M. Jones <rjones@redhat.com>.
|
||||
*
|
||||
* Note that we use ordinary OCaml ints, which means this program is
|
||||
* limited to: ~1TB disks for 32 bit machines, or effectively unlimited
|
||||
* for 64 bit machines.
|
||||
*)
|
||||
|
||||
open ExtList
|
||||
open Scanf
|
||||
open Printf
|
||||
|
||||
type op = Read | Write
|
||||
|
||||
(* If 'true' then print debug messages. *)
|
||||
let debug = false
|
||||
|
||||
(* Width of each row (in sectors) in the output. *)
|
||||
let row_size = 64
|
||||
|
||||
(* Desirable alignment (sectors). *)
|
||||
let alignment = 8
|
||||
|
||||
(* Height (in 1/72 inch) of the final image. *)
|
||||
let height = 6.*.72.
|
||||
|
||||
(* Width (in 1/72 inch) of the final image. *)
|
||||
let width = 6.*.72.
|
||||
|
||||
(* Reserve at left for the sector number (comes out of width). *)
|
||||
let sn_width = 36.
|
||||
|
||||
let input =
|
||||
if Array.length Sys.argv = 2 then
|
||||
Sys.argv.(1)
|
||||
else
|
||||
failwith "usage: tracetops filename.qtr"
|
||||
|
||||
(* Read the input file. *)
|
||||
let nb_sectors, accesses =
|
||||
let chan = open_in input in
|
||||
let nb_sectors =
|
||||
let summary = input_line chan in
|
||||
if String.length summary < 1 || summary.[0] <> 'S' then
|
||||
failwith (sprintf "%s: input is not a qemu block device trace file"
|
||||
input);
|
||||
sscanf summary "S %d" (fun x -> x) in
|
||||
|
||||
if nb_sectors mod row_size <> 0 then
|
||||
failwith (sprintf "input nb_sectors (%d) not divisible by row size (%d)"
|
||||
nb_sectors row_size);
|
||||
|
||||
(* Read the reads and writes from the remainder of the file. *)
|
||||
let accesses = ref [] in
|
||||
let rec loop () =
|
||||
let line = input_line chan in
|
||||
let rw, s, n = sscanf line "%c %d %d" (fun rw s n -> (rw, s, n)) in
|
||||
let rw =
|
||||
match rw with
|
||||
| 'R' -> Read | 'W' -> Write
|
||||
| c -> failwith
|
||||
(sprintf "%s: error reading input: got '%c', expecting 'R' or 'W'"
|
||||
input c) in
|
||||
if n < 0 || s < 0 || s+n > nb_sectors then
|
||||
failwith (sprintf "%s: s (%d), n (%d) out of range" input s n);
|
||||
let aligned = s mod alignment = 0 && n mod alignment = 0 in
|
||||
accesses := (rw, aligned, s, n) :: !accesses;
|
||||
loop ()
|
||||
in
|
||||
(try loop () with
|
||||
| End_of_file -> ()
|
||||
| Scan_failure msg ->
|
||||
failwith (sprintf "%s: error reading input: %s" input msg)
|
||||
);
|
||||
close_in chan;
|
||||
|
||||
let accesses = List.rev !accesses in
|
||||
|
||||
if debug then (
|
||||
eprintf "%s: nb_sectors = %d, accesses = %d\n"
|
||||
input nb_sectors (List.length accesses)
|
||||
);
|
||||
|
||||
nb_sectors, accesses
|
||||
|
||||
let ranges =
|
||||
(* Given the number of sectors, make the row array. *)
|
||||
let nr_rows = nb_sectors / row_size in
|
||||
let rows = Array.make nr_rows false in
|
||||
|
||||
List.iter (
|
||||
fun (_, _, s, n) ->
|
||||
let i0 = s / row_size in
|
||||
let i1 = (s+n-1) / row_size in
|
||||
for i = i0 to i1 do rows.(i) <- true done;
|
||||
) accesses;
|
||||
|
||||
(* Coalesce rows into a list of ranges of rows we will draw. *)
|
||||
let rows = Array.to_list rows in
|
||||
let rows = List.mapi (fun i v -> (v, i)) rows in
|
||||
let ranges =
|
||||
(* When called, we are in the middle of a range which started at i0. *)
|
||||
let rec loop i0 = function
|
||||
| (false, _) :: (false, _) :: (true, i1) :: []
|
||||
| _ :: (_, i1) :: []
|
||||
| (_, i1) :: [] ->
|
||||
[i0, i1]
|
||||
| (false, _) :: (false, _) :: (true, _) :: rest
|
||||
| (false, _) :: (true, _) :: rest
|
||||
| (true, _) :: rest ->
|
||||
loop i0 rest
|
||||
| (false, i1) :: rest ->
|
||||
let i1 = i1 - 1 in
|
||||
let rest = List.dropwhile (function (v, _) -> not v) rest in
|
||||
(match rest with
|
||||
| [] -> [i0, i1]
|
||||
| (_, i2) :: rest -> (i0, i1) :: loop i2 rest)
|
||||
| [] -> assert false
|
||||
in
|
||||
loop 0 (List.tl rows) in
|
||||
|
||||
if debug then (
|
||||
eprintf "%s: rows = %d (ranges = %d)\n" input nr_rows (List.length ranges);
|
||||
List.iter (
|
||||
fun (i0, i1) ->
|
||||
eprintf " %d - %d (rows %d - %d)\n"
|
||||
(i0 * row_size) ((i1 + 1) * row_size - 1) i0 i1
|
||||
) ranges
|
||||
);
|
||||
|
||||
ranges
|
||||
|
||||
(* Locate where we will draw the rows and cells in the final image. *)
|
||||
let iter_rows, mapxy, row_height, cell_width =
|
||||
let nr_ranges = List.length ranges in
|
||||
let nr_breaks = nr_ranges - 1 in
|
||||
let nr_rows =
|
||||
List.fold_left (+) 0 (List.map (fun (i0,i1) -> i1-i0+1) ranges) in
|
||||
let nr_rnb = nr_rows + nr_breaks in
|
||||
let row_height = height /. float nr_rnb in
|
||||
let cell_width = (width -. sn_width) /. float row_size in
|
||||
|
||||
if debug then (
|
||||
eprintf "number of rows and breaks = %d\n" nr_rnb;
|
||||
eprintf "row_height x cell_width = %g x %g\n" row_height cell_width
|
||||
);
|
||||
|
||||
(* Create a higher-order function to iterate over the rows. *)
|
||||
let rec iter_rows f =
|
||||
let rec loop row = function
|
||||
| [] -> ()
|
||||
| (i0,i1) :: rows ->
|
||||
for i = i0 to i1 do
|
||||
let y = float (row+i-i0) *. row_height in
|
||||
f y (Some i)
|
||||
done;
|
||||
(* Call an extra time for the break. *)
|
||||
let y = float (row+i1-i0+1) *. row_height in
|
||||
if rows <> [] then f y None;
|
||||
(* extra +1 here is to skip the break *)
|
||||
loop (row+i1-i0+1+1) rows
|
||||
in
|
||||
loop 0 ranges
|
||||
in
|
||||
|
||||
(* Create a hash which maps from the row number to the position
|
||||
* where we draw the row. If the row is not drawn, the hash value
|
||||
* is missing.
|
||||
*)
|
||||
let row_y = Hashtbl.create nr_rows in
|
||||
iter_rows (
|
||||
fun y ->
|
||||
function
|
||||
| Some i -> Hashtbl.replace row_y i y
|
||||
| None -> ()
|
||||
);
|
||||
|
||||
(* Create a function which maps from the sector number to the final
|
||||
* position that we will draw it.
|
||||
*)
|
||||
let mapxy s =
|
||||
let r = s / row_size in
|
||||
let y = try Hashtbl.find row_y r with Not_found -> assert false in
|
||||
let x = sn_width +. cell_width *. float (s mod row_size) in
|
||||
x, y
|
||||
in
|
||||
|
||||
iter_rows, mapxy, row_height, cell_width
|
||||
|
||||
(* Start the PostScript file. *)
|
||||
let () =
|
||||
printf "%%!PS-Adobe-3.0 EPSF-3.0\n";
|
||||
printf "%%%%BoundingBox: -10 -10 %g %g\n"
|
||||
(width +. 10.) (height +. row_height +. 20.);
|
||||
printf "%%%%Creator: tracetops.ml (part of libguestfs)\n";
|
||||
printf "%%%%Title: %s\n" input;
|
||||
printf "%%%%LanguageLevel: 2\n";
|
||||
printf "%%%%Pages: 1\n";
|
||||
printf "%%%%Page: 1 1\n";
|
||||
printf "\n";
|
||||
|
||||
printf "/min { 2 copy gt { exch } if pop } def\n";
|
||||
printf "/max { 2 copy lt { exch } if pop } def\n";
|
||||
|
||||
(* Function for drawing cells. *)
|
||||
printf "/cell {\n";
|
||||
printf " newpath\n";
|
||||
printf " moveto\n";
|
||||
printf " %g 0 rlineto\n" cell_width;
|
||||
printf " 0 %g rlineto\n" row_height;
|
||||
printf " -%g 0 rlineto\n" cell_width;
|
||||
printf " closepath\n";
|
||||
printf " gsave fill grestore 0.75 setgray stroke\n";
|
||||
printf "} def\n";
|
||||
|
||||
(* Define colours for different cell types. *)
|
||||
printf "/unalignedread { 0.95 0.95 0 setrgbcolor } def\n";
|
||||
printf "/unalignedwrite { 0.95 0 0 setrgbcolor } def\n";
|
||||
printf "/alignedread { 0 0.95 0 setrgbcolor } def\n";
|
||||
printf "/alignedwrite { 0 0 0.95 setrgbcolor } def\n";
|
||||
|
||||
(* Get width of text. *)
|
||||
printf "/textwidth { stringwidth pop } def\n";
|
||||
|
||||
(* Draw the outline. *)
|
||||
printf "/outline {\n";
|
||||
printf " newpath\n";
|
||||
printf " %g 0 moveto\n" sn_width;
|
||||
printf " %g 0 lineto\n" width;
|
||||
printf " %g %g lineto\n" width height;
|
||||
printf " %g %g lineto\n" sn_width height;
|
||||
printf " closepath\n";
|
||||
printf " 0.5 setlinewidth 0.3 setgray stroke\n";
|
||||
printf "} def\n";
|
||||
|
||||
(* Draw the outline breaks. *)
|
||||
printf "/breaks {\n";
|
||||
iter_rows (
|
||||
fun y ->
|
||||
function
|
||||
| Some _ -> ()
|
||||
| None ->
|
||||
let f xmin xmax =
|
||||
let yll = y +. row_height /. 3. -. 2. in
|
||||
let ylr = y +. row_height /. 2. -. 2. in
|
||||
let yur = y +. 2. *. row_height /. 3. in
|
||||
let yul = y +. row_height /. 2. in
|
||||
printf " newpath\n";
|
||||
printf " %g %g moveto\n" xmin yll;
|
||||
printf " %g %g lineto\n" xmax ylr;
|
||||
printf " %g %g lineto\n" xmax yur;
|
||||
printf " %g %g lineto\n" xmin yul;
|
||||
printf " closepath\n";
|
||||
printf " 1 setgray fill\n";
|
||||
printf " newpath\n";
|
||||
printf " %g %g moveto\n" xmin yll;
|
||||
printf " %g %g lineto\n" xmax ylr;
|
||||
printf " %g %g moveto\n" xmax yur;
|
||||
printf " %g %g lineto\n" xmin yul;
|
||||
printf " closepath\n";
|
||||
printf " 0.5 setlinewidth 0.3 setgray stroke\n"
|
||||
in
|
||||
f (sn_width -. 6.) (sn_width +. 6.);
|
||||
f (width -. 6.) (width +. 6.)
|
||||
);
|
||||
printf "} def\n";
|
||||
|
||||
(* Draw the labels. *)
|
||||
printf "/labels {\n";
|
||||
printf " /Courier findfont\n";
|
||||
printf " 0.75 %g mul 10 min scalefont\n" row_height;
|
||||
printf " setfont\n";
|
||||
iter_rows (
|
||||
fun y ->
|
||||
function
|
||||
| Some i ->
|
||||
let sector = i * row_size in
|
||||
printf " newpath\n";
|
||||
printf " /s { (%d) } def\n" sector;
|
||||
printf " %g s textwidth sub 4 sub %g moveto\n" sn_width (y +. 2.);
|
||||
printf " s show\n"
|
||||
| None -> ()
|
||||
);
|
||||
printf "} def\n";
|
||||
|
||||
(* Print the key. *)
|
||||
printf "/key {\n";
|
||||
printf " /Times-Roman findfont\n";
|
||||
printf " 10. scalefont\n";
|
||||
printf " setfont\n";
|
||||
let x = sn_width and y = height +. 10. in
|
||||
printf " unalignedwrite %g %g cell\n" x y;
|
||||
let x = x +. cell_width +. 4. in
|
||||
printf " newpath %g %g moveto (unaligned write) 0.3 setgray show\n" x y;
|
||||
let x = x +. 72. in
|
||||
printf " unalignedread %g %g cell\n" x y;
|
||||
let x = x +. cell_width +. 4. in
|
||||
printf " newpath %g %g moveto (unaligned read) 0.3 setgray show\n" x y;
|
||||
let x = x +. 72. in
|
||||
printf " alignedwrite %g %g cell\n" x y;
|
||||
let x = x +. cell_width +. 4. in
|
||||
printf " newpath %g %g moveto (aligned write) 0.3 setgray show\n" x y;
|
||||
let x = x +. 72. in
|
||||
printf " alignedread %g %g cell\n" x y;
|
||||
let x = x +. cell_width +. 4. in
|
||||
printf " newpath %g %g moveto (aligned read) 0.3 setgray show\n" x y;
|
||||
printf "} def\n";
|
||||
|
||||
printf "\n"
|
||||
|
||||
(* Draw the accesses. *)
|
||||
let () =
|
||||
(* Sort the accesses so unaligned ones are displayed at the end (on
|
||||
* top of aligned ones) and writes on top of reads. This isn't
|
||||
* really perfect, but it'll do.
|
||||
*)
|
||||
let cmp (rw, aligned, s, n) (rw', aligned', s', n') =
|
||||
let r = compare rw rw' (* Write later *) in
|
||||
if r <> 0 then r else (
|
||||
let r = compare aligned' aligned (* unaligned later *) in
|
||||
if r <> 0 then r else
|
||||
compare (n, s) (n', s')
|
||||
)
|
||||
in
|
||||
let accesses = List.sort ~cmp accesses in
|
||||
|
||||
List.iter (
|
||||
fun op ->
|
||||
let col, s, n =
|
||||
match op with
|
||||
| Read, false, s, n ->
|
||||
"unalignedread", s, n
|
||||
| Write, false, s, n ->
|
||||
"unalignedwrite", s, n
|
||||
| Read, true, s, n ->
|
||||
"alignedread", s, n
|
||||
| Write, true, s, n ->
|
||||
"alignedwrite", s, n in
|
||||
for i = s to s+n-1 do
|
||||
let x, y = mapxy i in
|
||||
printf "%s %g %g cell\n" col x y
|
||||
done;
|
||||
printf "\n"
|
||||
) accesses
|
||||
|
||||
(* Finish off the PostScript output. *)
|
||||
let () =
|
||||
printf "outline breaks labels key\n";
|
||||
printf "%%%%EOF\n"
|
||||
Reference in New Issue
Block a user