1package Test::Parser::SysbenchFileIO;
2
3=head1 NAME
4
5Test::Parser::SysbenchFileIO - Perl module to parse output from Sysbench --test=fileio
6
7=head1 SYNOPSIS
8
9    use Test::Parser::SysbenchFileIO;
10    my $parser = new Test::Parser::SysbenchFileIO;
11    $parser->parse($text);
12
13    $parser->to_xml();
14
15Additional information is available from the subroutines listed below
16and from the L<Test::Parser> baseclass.
17
18=head1 DESCRIPTION
19
20This module provides a way to parse and neatly display information gained from the
21Sysbench FileIO test.  This module will parse the output given by this command and
22commands similar to it:  `sysbench --test=fileio > fileio.output`  The fileio.output contains
23the necessary information that SysbenchFileIO is able to parse.
24
25=head1 FUNCTIONS
26
27Also see L<Test::Parser> for functions available from the base class.
28
29=cut
30
31use strict;
32use warnings;
33use Test::Parser;
34
35@Test::Parser::SysbenchFileIO::ISA = qw(Test::Parser);
36use base 'Test::Parser';
37
38use fields qw(
39              data
40              );
41
42use vars qw( %FIELDS $AUTOLOAD $VERSION );
43our $VERSION = '1.7';
44
45
46=head2 new()
47
48	Purpose: Create a new Test::Parser::SysbenchFileIO instance
49	Input: None
50	Output: SysbenchFileIO object
51
52=cut
53sub new {
54    my $class = shift;
55    my Test::Parser::SysbenchFileIO $self = fields::new($class);
56    $self->SUPER::new();
57
58    $self->testname('sysbench');
59    $self->type('unit');
60    $self->description('A variety of tests');
61    $self->summary('Lots of things');
62    $self->license('FIXME');
63    $self->vendor('FIXME');
64    $self->release('FIXME');
65    $self->url('FIXME');
66    $self->platform('FIXME');
67
68    $self->{data} = ();
69
70    return $self;
71}
72
73
74=head2 data()
75
76	Purpose: Return a hash representation of the Sysbench data
77	Input: None
78	Output: SysbenchFileIO data
79
80=cut
81sub data {
82    my $self = shift;
83    if (@_) {
84        $self->{data} = @_;
85    }
86    return {sysbench => {data => $self->{data}}};
87}
88
89
90=head2 parse_line()
91
92	Purpose: Parse Sysbench --test=fileio log files.  This method override's the default parse_line() of Test::Parser
93	Input: String (one line of log file)
94	Output: 1
95
96=cut
97sub parse_line {
98    my $self = shift;
99    my $line = shift;
100
101    my @labels = ();
102    my @keys = ();
103    my $size = 0;
104
105    #
106    # Trim any leading and trailing whitespaces.
107    #
108    $line =~ s/(^\s+|\s+$)//g;
109
110    # Determine what info we have in the line...
111    if ($line =~ /^Number .*?threads:(.+)/) {
112        $keys[1] = $1;
113        $labels[1] = 'num_threads';
114        $size = 1;
115    }
116    elsif ($line =~ /^sysbench v(.+):/) {
117        $self->testname('sysbench');
118        $self->version($1);
119    }
120    elsif ($line =~ /^Doing c(.+)/) {
121        $keys[1] = $1;
122        $labels[1] = 'desc';
123        $size = 1;
124    }
125
126    elsif ($line =~ /^Extra .*?flags:(.+)/) {
127        $keys[1] = $1;
128        $labels[1] = 'file_open_flags';
129        $size = 1;
130    }
131
132    # These are done together as there are 2 pieces of information on each line
133    elsif ($line =~ /^(.+).*?files, (\d+)(\w+).*?each/) {
134        $keys[1] = $1;
135        $labels[1] = 'num_files';
136        $keys[2] = $2;
137        $labels[2] = 'file_size';
138        $keys[3] = $3;
139        $labels[3] = 'file_size_units';
140        $size = 3;
141    }
142
143    elsif ($line =~ /^(\d+)(\w+).*?total file size/) {
144        $keys[1] = $1;
145        $labels[1] = 'total_file_size';
146        $keys[2] = $2;
147        $labels[2] = 'total_file_size_units';
148        $size = 2;
149    }
150
151    elsif ($line =~ /^Block size (\d+)(\w+).*/) {
152        $keys[1] = $1;
153        $labels[1] = 'block_size';
154        $keys[2] = $2;
155        $labels[2] = 'block_size_units';
156        $size = 2;
157    }
158
159    elsif ($line =~ /^Number .*?IO:(.+)/) {
160        $keys[1] = $1;
161        $labels[1] = 'num_random_req';
162        $size = 1;
163    }
164
165    elsif ($line =~ /^Read.*?test:(.+)/) {
166        $keys[1] = $1;
167        $labels[1] = 'rw_ratio';
168        $size = 1;
169    }
170
171    # These are done together as there are 2 pieces of information on each line
172    elsif ($line =~ /^Periodic FSYNC(.+), calling fsync\(\) each (.+) requests/) {
173        $keys[1] = $1;
174        $labels[1] = 'fsync_status';
175        $keys[2] = $2;
176        $labels[2] = 'fsync_freq';
177        $size = 2;
178    }
179
180    elsif ($line =~ /^Calling .*?test,(.+)./) {
181        $keys[1] = $1;
182        $labels[1] = 'fsync_end';
183        $size = 1;
184    }
185
186    elsif ($line =~ /^Using (.+) mode/) {
187        $keys[1] = $1;
188        $labels[1] = 'io_mode';
189        $size = 1;
190    }
191
192    elsif ($line =~ /^Doing (.+) test/) {
193        $keys[1] = $1;
194        $labels[1] = 'test_run';
195        $size = 1;
196    }
197
198    elsif ($line =~ /(.+).*Requests/) {
199        $keys[1] = $1;
200        $labels[1] = 'op_req_rate';
201        $size = 1;
202    }
203
204    elsif ($line =~ /^total .*?time:\s+([\.\d]+)(\w+)/) {
205        $keys[1] = $1;
206        $labels[1] = 'total_time';
207        $keys[2] = $2;
208        $labels[2] = 'total_time_units';
209        $size = 2;
210    }
211
212    elsif ($line =~ /^total .*?events:\s+(.+)/) {
213        $keys[1] = $1;
214        $labels[1] = 'total_events';
215        $size = 1;
216    }
217
218    elsif ($line =~ /^total .*?execution:\s+(.+)/) {
219        $keys[1] = $1;
220        $labels[1] = 'total_exec';
221        $size = 1;
222    }
223
224    elsif ($line =~ /^min:\s+([\.\d]+)(\w+)/) {
225        $keys[1] = $1;
226        $labels[1] = 'pr_min';
227        $keys[2] = $2;
228        $labels[2] = 'pr_min_units';
229        $size = 2;
230    }
231
232    elsif ($line =~ /^avg:\s+([\.\d]+)(\w+)/) {
233        $keys[1] = $1;
234        $labels[1] = 'pr_avg';
235        $keys[2] = $2;
236        $labels[2] = 'pr_avg_units';
237        $size = 2;
238    }
239
240    elsif ($line =~ /^max:\s+([\.\d]+)(\w+)/) {
241        $keys[1] = $1;
242        $labels[1] = 'pr_max';
243        $keys[2] = $2;
244        $labels[2] = 'pr_max_units';
245        $size = 2;
246    }
247
248    elsif ($line =~ /^approx. .*?tile:\s+([\.\d]+)(\w+)/) {
249        $keys[1] = $1;
250        $labels[1] = 'pr_95';
251        $keys[2] = $2;
252        $labels[2] = 'pr_95_units';
253        $size = 2;
254    }
255
256    # These are done together as there are 2 pieces of information on each line
257    elsif ($line =~ /^events .*?:(.+)\/(.+)/) {
258        $keys[1] = $1;
259        $labels[1] = 'event_avg';
260        $keys[2] = $2;
261        $labels[2] = 'event_stddev';
262        $size = 2;
263    }
264
265    # These are done together as there are 2 pieces of information on each line
266    elsif ($line =~ /^execution .*?:(.+)\/(.+)/) {
267        $keys[1] = $1;
268        $labels[1] = 'exec_avg';
269        $keys[2] = $2;
270        $labels[2] = 'exec_stddev';
271        $size = 2;
272    }
273
274    # These are done together as there are 4 pieces of information on each line
275    elsif ($line =~ /^Operations performed: (.+) Read, (.+) Write, (.+) Other = (.+) Total/) {
276        $keys[1] = $1;
277        $labels[1] = 'ops_reads';
278        $keys[2] = $2;
279        $labels[2] = 'ops_write';
280        $keys[3] = $3;
281        $labels[3] = 'ops_other';
282        $keys[4] = $4;
283        $labels[4] = 'ops_total';
284        $size = 4;
285    }
286
287    # These are done together as there are 4 pieces of information on each line
288    elsif ($line =~ /^Read ([\.\d]+)(\w+)\s+Written\s+([\.\d]+)(\w+).*\s+transferred\s+([\.\d]+)(\w+)\s+\(([\.\d]+)(\w+)/) {
289        $keys[1] = $1;
290        $labels[1] = 'op_read';
291        $keys[2] = $2;
292        $labels[2] = 'op_read_units';
293        $keys[3] = $3;
294        $labels[3] = 'op_written';
295        $keys[4] = $4;
296        $labels[4] = 'op_written_units';
297        $keys[5] = $5;
298        $labels[5] = 'op_trans_total';
299        $keys[6] = $6;
300        $labels[6] = 'op_trans_total_units';
301        $keys[7] = $7;
302        $labels[7] = 'op_trans_rate';
303        $keys[8] = $8;
304        $labels[8] = 'op_trans_rate_units';
305        $size = 8;
306    }
307
308    my $do_units = 0;
309
310    for (my $tekey = 0; $tekey <= $size; $tekey++)
311    {
312        if( $tekey+1 <= $size ) {
313            my $check_me = $labels[$tekey+1];
314            my $orig = $labels[$tekey];
315            my $units = $orig;
316            $units .= "_units";
317            if( $check_me eq $units ) {
318                $do_units = 1;
319            }
320        }
321        if ( defined($labels[$tekey]) ) {
322            $keys[$tekey] =~ s/(^\s+|\s+$)//g;
323            my $col = 0;
324            if ($do_units == 1) {
325                $keys[$tekey+1] =~ s/(^\s+|\s+$)//g;
326                $col = $self->add_column( $labels[$tekey], $keys[$tekey+1] );
327                $self->add_data( $keys[$tekey], $col );
328
329                $tekey++;
330            }
331            else {
332                $col = $self->add_column( $labels[$tekey] );
333                $self->add_data( $keys[$tekey], $col );
334            }
335            $do_units=0;
336        }
337    }
338    return 1;
339}
340
341
3421;
343__END__
344
345=head1 AUTHOR
346
347John Daiker <daikerjohn@gmail.com>
348
349=head1 COPYRIGHT
350
351Copyright (C) 2006 John Daiker & Open Source Development Labs, Inc.
352All Rights Reserved.
353
354This script is free software; you can redistribute it and/or modify it
355under the same terms as Perl itself.
356
357=head1 SEE ALSO
358
359L<Test::Parser>
360
361=end
362