How to instrument an existing binary application¶
1. Prerequisites¶
- If you are a new OMF user, make sure that you have read and understood at least the first couple of tutorials on our basic tutorial pages
- Make sure to use the latest OMF 5.3 (check with your testbed operator, or install OMF 5.3 on your own testbed)
- Make sure that your experimental resources (e.g. PC nodes) have at least OML 2.3.9 installed (see the OML installation pages)
2. Goal¶
How to write an OML Ruby application to wrap around another application?
As a user, you want to use applications in your experiments and instruments them to collect measurement while they are running. However sometime, you do not have the source code of these applications, and only have their executable binary.
If these applications produce some outputs on standard-out while they run, then you can capture these outputs as measurements and collect them using OML. In order to do that you need to:
- A - create a wrapper around your existing binary application, which will capture its output and send them to an OML collection server
- B - create an OMF Application Definition for this wrapper, which will allow you to use that wrapper in an OMF Experiment Description
- C - use that wrapper in your experiment
This tutorial shows you how to realise these steps.
3. Scenario¶
The experiment scenario and system overview for this tutorial are illustrated in the following figure:
We will use the application wlanconfig has the example of a binary application to instrument. When run with the command wlanconfig ath0 list, this application writes (on its standard output) a line with the MAC address of any WIFI device that the interface ath0 has detected, followed by various statistics about the link quality towards that device. We will capture these lines as our measurements.
4. Step A - Creating a Wrapper around the application binary wlanconfig¶
- We use the Ruby language to create the wrapper application called
wlanmonitor-simple.rb
- The complete Ruby source code (70 lines without comments) for this wrapper is attached here: wlanmonitor-simple.rb
- First we make sure that our wrapper is using the
oml4rlibrary which is part of the OML Library- If you've installed OML from Debian/Ubuntu packages, you can find it at
/usr/share/liboml2-dev/oml4r.rb. Copy or symlink it to the path where you write your wrapper, or set the Ruby environment to include the path to the library. - If you've compiled OML from source, the library is at
/usr/share/oml2/oml4r.rb - The first lines of the wrapper has a require statement:
- If you've installed OML from Debian/Ubuntu packages, you can find it at
1 require "oml4r"
- Then we define the schema of the Measurement Point we would like to create
- here we call our Measurement Point
MPStatand it is of the classOML4R:MPBase - this is the description of each sample that you would like to collect and store
- this is also the description of the schema for the database table in each your samples will be stored
- here we call our Measurement Point
1 class MPStat < OML4R::MPBase
2 name :wlanstat
3 param :src_addr
4 param :dst_addr
5 param :aid, :type => :long
6 param :channel, :type => :long
7 param :rate
8 param :rssi, :type => :long
9 param :dbm, :type => :long
10 param :idle, :type => :long
11 param :txseq, :type => :long
12 param :rxseq, :type => :long
13 # wlanconfig returns other metrics which we ignore here
14 end
- Then we define the class for our Wrapper, we call it
Wrapper:
1 class Wrapper
2 ...
3 end
- Inside that Wrapper class we define a
Initializemethod- this method parses the command line options for our wrapper application
- this method also initialises the OML4R Library to allow future measurement to be forwarded to it
- Line 2-3: initialise some variables for our wrapper
- Line 4-8: initialise the OML4R Library
- Line 4:
appIDis the name of your application (wlanconfig here), which will also be the used as a prefix to name the resulting database table - Line 6-7: we define the command line options for our wrapper and store their values into some variables
- Line 4:
1 def initialize(args)
2 @interface = nil
3 @interval = 1
4 OML4R::init(args, :appID => "wlanconfig") do |argParser|
5 argParser.banner = "\nExecute a wrapper around wlanconfig\n Use -h or --help for a list of options\n\n"
6 argParser.on("-i", "--interface IFNAME","Name of Interface to monitor") { |name| @interface = name }
7 argParser.on("-s", "--sampling DURATION", "Interval in second between collected samples") { |time| @interval = time }
8 end
9 unless @interface != nil
10 raise "You did not specify an interface to monitor! (-i option)"
11 end
12 end
- Still inside that Wrapper class we define a
process_outputmethod- this method parses each lines that the wlanconfig application writes on its standard output
- it constructs the measurement sample to send for OML collection using the information from the parsed lines
- Line 2: turn the output of wlanconfig into an array where each entry is an line of text
- Line 3: delete the first line which contains only label information
- Line 4-9: for each line
- we parse the line using white-space as separator
- we construct a measurement sample using selected columns in that line
- we inject that measurement sample into the measurement Point which we defined earlier
1 def process_output(output)
2 lines = output.split("\n")
3 labels = lines.delete_at(0)
4 lines.each { |row|
5 column = row.split(" ")
6 MPStat.inject("#{column[0]}", column[1], column[2],
7 "#{column[3]}", column[4], column[5],
8 column[6], column[7], column[8])
9 }
10 end
- Still inside that Wrapper class we define a
startmethod- this method will run the wlanconfig command and process its output, in an infinite loop
- Line 3-4: run the command line "
/usr/sbin/wlanconfig <interface> list" - Line 5: call the
process_outputmethod on the output of that command - Line 6: sleep for some time and loop again
1 def start()
2 while true
3 cmd = "/usr/sbin/wlanconfig #{@interface} list"
4 output = `#{cmd}`
5 process_output(output)
6 sleep @interval.to_i
7 end
8 end
- Finally, outside the Wrapper class definition, we write the code that will start this wrapper application
1 begin
2 app = Wrapper.new(ARGV)
3 app.start()
4 rescue Exception => ex
5 puts "Received an Exception when executing the wrapper!"
6 puts "The Exception is: #{ex}\n"
7 end
- The complete Ruby source code (70 lines without comments) for this wrapper is attached here: wlanmonitor-simple.rb
- Install this wrapper to your experimental resources (e.g. a PC-node)
- copy this wrapper to the
/usr/bin/directory of your experimental resource - If you have OML installed on your resource, the OML4R library should be present there as well, if not, copy the oml4r.rb file to the same
/usr/bindirectory - OMF provides a way for automatically performing this installation, to keep this tutorial short we are not describing it here, have a look at the tutorial on "How to install your own application on your resources within an experiment"
- copy this wrapper to the
5. Step B - Create an OMF Application Definition for this wrapper¶
- As explained on the usage overview page, to be able to use an application (such ash the above wrapper) in you OMF experiment, you need to write an OMF Application Definition for it
- You can find a detailed tutorial on how to do so on the "How to use your own or a 3rd party application with OMF" tutorial page
- Here is the source code for the OMF Application Definition for the above wrapper. Again, please refer to the mentioned tutorial page to get a full explanation of this source code. This Application Definition is also attached here: wlanmonitor_app.rb
1 defApplication('wlanmonitor_app', 'wlanmonitor') do |a|
2 a.path = "/usr/bin/wlanmonitor-simple.rb"
3 a.version(1, 2, 0)
4 a.shortDescription = "Wrapper around wlanconfig's list mode"
5 a.description = <<TEXT
6 This is a wrapper around the wlanconfig command used in list mode.
7 This application is using OML4R part of OML v2.3 or v2.4
8 TEXT
9
10 a.defProperty('interface', 'Interface to listen on', 'i', {:type => :string, :dynamic => false})
11 a.defProperty('sampling', 'Sampling interval in sec', 's', {:type => :integer, :dynamic => false})
12
13 a.defMeasurement('wlanstat') do |m|
14 m.defMetric('src_addr',:string)
15 m.defMetric('dst_addr',:string)
16 m.defMetric('aid',:long)
17 m.defMetric('channel',:long)
18 m.defMetric('rate',:string)
19 m.defMetric('rssi',:long)
20 m.defMetric('dbm',:long)
21 m.defMetric('idle',:long)
22 m.defMetric('txseq',:long)
23 end
24 end
6. Use the Wrapper in your Experiment¶
- Here is the complete Experiment Description for the scenario described above, where the Wrapper application is running on a single resource or node. In this Experiment Description, we also make use of OMF capability to plot graphs at experiment runtime to illustrate the experiment results.
- If you do not understand this Experiment Description, please refer to the following tutorials which have detailed information:
- This Experiment Definition is also attached here: experiment.rb
1 # Some experiment properties
2 defProperty('node', "omf.nicta.node29", "ID of a node")
3 defProperty('mode1', "adhoc", "wifi mode for 1st node")
4 defProperty('wifi', "g", "wifi type to use")
5 defProperty('channel', "1", "wifi channel to use")
6
7 # Define the group of resource that 'observe' the wireless medium
8 defGroup('Observers', property.node) {|node|
9 node.addApplication("wlanmonitor_app") {|app|
10 app.setProperty('interface', 'ath0')
11 app.setProperty('sampling', 3)
12 app.measure('wlanstat')
13 }
14 node.net.w0.mode = property.mode1
15 node.net.w0.type = property.wifi
16 node.net.w0.channel = property.channel
17 node.net.w0.essid = "expmonitor"
18 node.net.w0.ip = "192.168.0.1"
19 }
20
21 # When all resources are up and applications are installed...
22 onEvent(:ALL_UP_AND_INSTALLED) do |event|
23 wait 10
24 allGroups.startApplications
25 wait 300
26 allGroups.stopApplications
27 Experiment.done
28 end
29
30 # Use the OMF-builtin graph plotting capabilities to plot RSSI
31 # (Received Signal Strength Indication) on the link towards
32 # the observed wireless devices...
33 addTab(:defaults)
34 addTab(:graph2) do |tab|
35 opts = { :postfix => %{This graph shows the RSSI.}, :updateEvery => 3 }
36 tab.addGraph("RSSI", opts) do |g|
37 data = Hash.new
38 mp = ms('wlanstat')
39 mp.project(:oml_ts_server, :src_addr, :dst_addr, :rssi).each do |sample|
40 time, src, dst, rssi = sample.tuple
41 data[dst] = [] if data[dst] == nil
42 data[dst] << [time, rssi] if src != dst
43 end
44 data.each do |d,v|
45 g.addLine(v, :label => d)
46 end
47 end
48 end
7. Run the experiment¶
- Prerequisites:
- On your resource (i.e. node "omf.nicta.node29"):
- Your 3rd party application ("wlanconfig") is installed at the path:
/usr/sbin/wlanconfig - Your Ruby Wrapper with OML support ("wlanmonitor-simple.rb") is installed at:
/usr/bin/wlanmonitor-simple - The OML 2.4 library (or newer) is installed
- The OML4R library is either installed (by default with OML) or installed by you at:
/usr/bin/oml4r.rb
- Your 3rd party application ("wlanconfig") is installed at the path:
- On your machine or testbed console:
- Your OMF Application Definition ("wlanmonitor_app.rb") is in the same directory as your experiment ("experiment.rb")
- On your resource (i.e. node "omf.nicta.node29"):
- You can run the above experiment with:
omf-5.3 exec experiment.rb
- Note:
- Refer to the the "Hello World" tutorial to learn how to access a testbed and run an experiment
- OMF has a feature which allows the automatic installation of all your application files onto your resource. The use of that feature is explained in detail in the "Use a 3rd party application" tutorial.
8. The Results¶
- The OMF Experiment Controller (EC) is capable of plotting user-defined graphs at experiment runtime, which are visible on the its runtime webpage.
- Please refer to the "Hello World" tutorial to find out how to access the EC's web page, and to the EC graph plotting feature to find out how to define graphs
- Assuming you ran the above experiment and pointed your web browser to the EC's web page, under the "Graph" tab, you should see a graph similar to this:
9. What is Next?¶
- Have a look at the other advanced OMF tutorials
- Go back for a refresh on the basic OMF tutorials
- Go back to the User Guide front page