Translate

Archives

Not your Grandfather's dd Utility!

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!

Comments are closed.