A recent article in Red Hat Magazine by Noah Gift and Grig Gheorghiu called “This isn’t your grandpappy’d dd command demonstrated how to use Python, the dd utility and the Google Chart API to produce a bar chart showing throughput at different block sizes. However the output from the Python script was not the actual graph but a URL which you then had to paste into a Web browser to view the resulting chart.
I though this script would be useful but did not want to have to cut and paste a URL into a Web browser so I decided to eliminate that step.
This Python script is loosely based on their script but uses the Python urllib libraries to connect to Google Charts to generate a PNG image file which is subsequently displayed using pyGTK+ routines.
#!/usr/bin/env python
import sys
import os
import commands
import re
from optparse import OptionParser
import urllib
import urllib2
import pygtk
pygtk.require('2.0')
import gtk
class DisplayGraph:
def delete_event(self, widget, event, data=None):
return False
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
self.window.set_border_width(10)
self.window.set_position(gtk.WIN_POS_CENTER)
self.window.set_title("Disk Throughput")
pixbuf = gtk.gdk.pixbuf_new_from_file("/tmp/dd.png")
os.remove("/tmp/dd.png")
self.image = gtk.Image()
self.image.set_from_pixbuf(pixbuf)
self.image.show()
self.window.add(self.image)
self.window.show()
def main(self):
gtk.main()
class GoogleChart:
def __init__(self):
self.gchart_url = "http://chart.apis.google.com/chart?"
self.gchart_type = "cht=bvs"
self.gchart_title = "&chtt="
self.gchart_data = "&chd=t:"
self.gchart_labels = "&chxl=0:|"
self.gchart_size = "&chs=400x250"
self.gchart_axis_labels = "&chxt=x,y,x,y"
self.gchart_axis_position = "&chxp=2,50|3,50"
self.gchart_bar_settings = "&chbh=30,15"
def title(self,title):
self.gchart_title = self.gchart_title + title
def write(self, data, labels, max_t):
self.gchart_data = self.gchart_data + data.rstrip(',')
self.gchart_labels = self.gchart_labels \
+ labels + "2:|Block%20Size|3:|Mb/s"
self.gchart_axis_range = "&chxr=1,0," + str(max_t+10.0)
self.gchart_scaling = "&chds=0," + str(max_t+10.0)
self.gchart_url += self.gchart_type \
+ self.gchart_title + self.gchart_size
self.gchart_url += self.gchart_bar_settings \
+ self.gchart_data + self.gchart_labels
self.gchart_url += self.gchart_axis_labels \
+ self.gchart_axis_position
self.gchart_url += self.gchart_axis_range \
+ self.gchart_scaling
opener = urllib2.urlopen(self.gchart_url)
if opener.headers['content-type'] != 'image/png':
raise BadContentTypeException('Server responded' \
'with a content-type of %s' \
% opener.headers['content-type'])
open("/tmp/dd.png", 'wb').write(opener.read())
def get_disk_throughput(device, blocksize):
blocksize = str(blocksize) + 'k'
cmd = "dd if=/dev/zero of=%s bs=%s" % (device,blocksize)
output = commands.getoutput(cmd)
throughput = 0
unit = ""
for line in output.split('n'):
s = re.search(' copied,.*, (\S+) (\S+)$', line)
if s:
throughput = s.group(1)
unit = s.group(2)
break
return (throughput, unit)
if __name__ == "__main__":
usage = "Usage: %prog options"
parser = OptionParser(usage=usage)
parser.add_option("-d", "--device", dest="device", \
help="Device to use. Disk data will be overwritten!")
(options, args) = parser.parse_args()
device = options.device
if not device:
parser.print_help()
sys.exit(1)
max_t = 0.0
# block sizes to test dd write
blocksizes = [128, 256, 512, 1024, 2048, 4096, 8192]
data=""
labels=""
for blocksize in blocksizes:
(t, u) = get_disk_throughput(device, blocksize)
if float(t) > max_t:
max_t = float(t)
data += str(t) + ","
labels += str(blocksize) + "k" + "|"
chart = GoogleChart()
chart.title(device)
chart.write(data, labels, max_t)
graph = DisplayGraph()
graph.main()
Here is a snapshot of a typical graph produced
BTW, this script was developed and tested on Fedora 9. Enjoy!


























