View | Details | Raw Unified | Return to bug 6015
Collapse All | Expand All

(-)a/misc/load_testing/benchmark_staff.pl (-1 / +388 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
# This script implements a basic benchmarking and regression testing
3
# utility for Koha
4
5
use strict;
6
use warnings;
7
BEGIN {
8
    # find Koha's Perl modules
9
    # test carefully before changing this
10
    use FindBin;
11
    eval { require "$FindBin::Bin/kohalib.pl" };
12
}
13
14
use Getopt::Long;
15
use HTTPD::Bench::ApacheBench;
16
use LWP::UserAgent;
17
use Data::Dumper;
18
use HTTP::Cookies;
19
use C4::Context;
20
use C4::Debug;
21
22
my ($help, $steps, $baseurl, $max_tries, $user, $password,$short_print);
23
GetOptions(
24
    'help'    => \$help,
25
    'steps:s'   => \$steps,
26
    'url:s' => \$baseurl,
27
    'user:s' => \$user,
28
    'password:s' => \$password,
29
    'maxtries:s' => \$max_tries,
30
    'short' => \$short_print,
31
);
32
my $concurrency = 30;
33
$max_tries=20 unless $max_tries;
34
# if steps not provided, run all tests
35
$steps='0123456789' unless $steps;
36
37
# if short is set, we will only give number for direct inclusion on the wiki
38
my $short_ms="|-\n|ON\n";
39
my $short_psec="|-\n|ON\n";
40
41
if ($help || !$baseurl || !$user || !$password) {
42
    print <<EOF
43
This script runs a benchmark of the staff interface. It benchmark 6 different pages:
44
\t1- the staff main page
45
\t2- the catalog detail page, with a random biblionumber
46
\t3- the catalog search page, using a term retrieved from one of the 10 first title/author in the database
47
\t4- the patron detail page, with a random borrowernumber
48
\t5- the patron search page, searching for "Jean"
49
\t6- the circulation itself, doing check-out and check-in of random items to random patrons
50
51
\t0 all those tests at once
52
parameters :
53
\thelp = this screen
54
\tsteps = which steps you want to run. 
55
\t\tDon't use it if you want to run all tests. enter 125 if you want to run tests 1, 2 and 5
56
\t\tThe "all those tests at once" is numbered 0,and will run all tests previously run.
57
\t\tIf you run only one step, it's useless to run the 0, you'll get the same result.
58
\turl = the URL or your staff interface
59
\tlogin = Koha login
60
\tpassword = Koha password
61
\tmaxtries = how many tries you want to do. Defaulted to 20
62
63
SAMPLE : ./benchmark_staff.pl --url=http://yourstaff.org/cgi-bin/koha/ --user=test --password=test --steps=12
64
65
EOF
66
;
67
exit;
68
}
69
70
71
# Authenticate via our handy dandy RESTful services
72
# and grab a cookie
73
my $ua = LWP::UserAgent->new();
74
my $cookie_jar = HTTP::Cookies->new();
75
my $cookie;
76
$ua->cookie_jar($cookie_jar);
77
my $resp = $ua->post( "$baseurl"."/svc/authentication" , {userid =>$user, password => $password} );
78
if( $resp->is_success ) {
79
    $cookie_jar->extract_cookies( $resp );
80
    $cookie = $cookie_jar->as_string;
81
    unless ($short_print) {
82
        print "Authentication successful\n";
83
        print "Auth:\n $resp->content" if $debug;
84
    }
85
}
86
87
# remove some unnecessary garbage from the cookie
88
$cookie =~ s/ path_spec; discard; version=0//;
89
$cookie =~ s/Set-Cookie3: //;
90
91
# Get some data to work with
92
my $dbh=C4::Context->dbh();
93
# grab some borrowernumbers
94
my $sth = $dbh->prepare("select max(borrowernumber) from borrowers");
95
$sth->execute;
96
my ($borrowernumber_max) = $sth->fetchrow;
97
my @borrowers;
98
for (my $i=1;$i<=$max_tries;$i++) {
99
    my $rand_borrowernumber = int(rand($borrowernumber_max)+1);
100
    push @borrowers,"$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber";
101
}
102
103
# grab some biblionumbers
104
$sth = $dbh->prepare("select max(biblionumber) from biblio");
105
$sth->execute;
106
my ($biblionumber_max) = $sth->fetchrow;
107
my @biblios;
108
for (my $i=1;$i<=$max_tries;$i++) {
109
    my $rand_biblionumber = int(rand($biblionumber_max)+1);
110
    push @biblios,"$baseurl/catalogue/detail.pl?biblionumber=$rand_biblionumber";
111
}
112
113
# grab some title and author, for random search
114
$sth = $dbh->prepare ("SELECT title, author FROM biblio LIMIT 10");
115
$sth->execute;
116
my ($title,$author);
117
my @searchwords;
118
while (($title,$author)=$sth->fetchrow) {
119
    push @searchwords,split / /, $author;
120
    push @searchwords,split / /, $title;
121
}
122
123
$sth = $dbh->prepare("select max(itemnumber) from items");
124
$sth->execute;
125
# find the biggest itemnumber
126
my ($itemnumber_max) = $sth->fetchrow;
127
128
$|=1;
129
unless ($short_print) {
130
    print "--------------\n";
131
    print "Koha STAFF benchmarking utility\n";
132
    print "--------------\n";
133
    print "Benchmarking with $max_tries occurences of each operation and $concurrency concurrent sessions \n";
134
}
135
#
136
# the global benchmark we do at the end...
137
#
138
my $b = HTTPD::Bench::ApacheBench->new;
139
$b->concurrency( $concurrency );
140
my $ro;
141
#
142
# STEP 1: mainpage : (very) low RDBMS dependency
143
#
144
if ($steps=~ /1/) {
145
    my $b0 = HTTPD::Bench::ApacheBench->new;
146
    $b0->concurrency( $concurrency );    my @mainpage;
147
    unless ($short_print) {
148
        print "Step 1: staff client main page     ";
149
    }
150
    for (my $i=1;$i<=$max_tries;$i++) {
151
        push @mainpage,"$baseurl/mainpage.pl";
152
    }
153
    my $run0 = HTTPD::Bench::ApacheBench::Run->new
154
        ({ urls => \@mainpage,
155
           cookies => [$cookie],
156
        });
157
    $b0->add_run($run0);
158
    $b->add_run($run0);
159
160
    # send HTTP request sequences to server and time responses
161
    $ro = $b0->execute;
162
    # calculate hits/sec
163
    if ($short_print) {
164
        $short_ms.= "|".$b0->total_time."\n";
165
        $short_psec.="|".(int((1000*$b0->total_requests/$b0->total_time)*1000)/1000)."\n";
166
    } else {
167
        print ("\t".$b0->total_time."ms\t".(int((1000*$b0->total_requests/$b0->total_time)*1000)/1000)." pages/sec\n");
168
        print "ALERT : ".$b0->total_responses_failed." failures\n" if $b0->total_responses_failed;
169
    }
170
} else {
171
    print "Skipping step 1\n";
172
}
173
174
#
175
# STEP 2: biblios
176
#
177
if ($steps=~ /2/) {
178
    my $b1 = HTTPD::Bench::ApacheBench->new;
179
    $b1->concurrency( $concurrency );
180
181
    unless ($short_print) {
182
        print "Step 2: catalog detail page        ";
183
    }
184
    my $run1 = HTTPD::Bench::ApacheBench::Run->new
185
        ({ urls => \@biblios,
186
           cookies => [$cookie],
187
        });
188
    $b1->add_run($run1);
189
    $b->add_run($run1);
190
191
    # send HTTP request sequences to server and time responses
192
    $ro = $b1->execute;
193
    # calculate hits/sec
194
    if ($short_print) {
195
        $short_ms.= "|".$b1->total_time."\n";
196
        $short_psec.="|".(int((1000*$b1->total_requests/$b1->total_time)*1000)/1000)."\n";
197
    } else {
198
        print ("\t".$b1->total_time."ms\t".(int((1000*$b1->total_requests/$b1->total_time)*1000)/1000)." biblios/sec\n");
199
        print "ALERT : ".$b1->total_responses_failed." failures\n" if $b1->total_responses_failed;
200
    }
201
} else {
202
    print "Skipping step 2\n";
203
}
204
#
205
# STEP 3: search
206
#
207
if ($steps=~ /3/) {
208
    my $b1 = HTTPD::Bench::ApacheBench->new;
209
    $b1->concurrency( $concurrency );
210
    unless ($short_print) {
211
        print "Step 3: catalogue search               ";
212
    }
213
    my @searches;
214
    for (my $i=1;$i<=$max_tries;$i++) {
215
        push @searches,"$baseurl/catalogue/search.pl?q=".@searchwords[int(rand(scalar @searchwords))];
216
    }
217
    my $run1 = HTTPD::Bench::ApacheBench::Run->new
218
        ({ urls => \@searches,
219
           cookies => [$cookie],
220
        });
221
    $b1->add_run($run1);
222
    $b->add_run($run1);
223
224
    # send HTTP request sequences to server and time responses
225
    $ro = $b1->execute;
226
    # calculate hits/sec
227
    if ($short_print) {
228
        $short_ms.= "|".$b1->total_time."\n";
229
        $short_psec.="|".(int((1000*$b1->total_requests/$b1->total_time)*1000)/1000)."\n";
230
    } else {
231
        print ("\t".$b1->total_time."ms\t".(int((1000*$b1->total_requests/$b1->total_time)*1000)/1000)." biblios/sec\n");
232
        print "ALERT : ".$b1->total_responses_failed." failures\n" if $b1->total_responses_failed;
233
    }
234
} else {
235
    print "Skipping step 3\n";
236
}
237
#
238
# STEP 4: borrowers
239
#
240
if ($steps=~ /4/) {
241
    my $b2 = HTTPD::Bench::ApacheBench->new;
242
    $b2->concurrency( $concurrency );
243
    unless ($short_print) {
244
        print "Step 5: patron detail page         ";
245
    }
246
    my $run2 = HTTPD::Bench::ApacheBench::Run->new
247
        ({ urls => \@borrowers,
248
           cookies => [$cookie],
249
        });
250
    $b2->add_run($run2);
251
    $b->add_run($run2);
252
253
    # send HTTP request sequences to server and time responses
254
    $ro = $b2->execute;
255
    # calculate hits/sec
256
    if ($short_print) {
257
        $short_ms.= "|".$b2->total_time."\n";
258
        $short_psec.="|".(int((1000*$b2->total_requests/$b2->total_time)*1000)/1000)."\n";
259
    } else {
260
        print ("\t".$b2->total_time."ms\t".(int((1000*$b2->total_requests/$b2->total_time)*1000)/1000)." borrowers/sec\n");
261
    }
262
} else {
263
    print "Skipping step 4\n";
264
}
265
266
#
267
# STEP 5: borrowers search
268
#
269
if ($steps=~ /5/) {
270
    my $b2 = HTTPD::Bench::ApacheBench->new;
271
    $b2->concurrency( $concurrency );
272
    unless ($short_print) {
273
        print "Step 5: patron search page             ";
274
    }
275
    for (my $i=1;$i<=$max_tries;$i++) {
276
    #     print "$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber\n";
277
        push @borrowers,"$baseurl/members/member.pl?member=jean";
278
    }
279
    my $run2 = HTTPD::Bench::ApacheBench::Run->new
280
        ({ urls => \@borrowers,
281
           cookies => [$cookie],
282
        });
283
    $b2->add_run($run2);
284
    $b->add_run($run2);
285
286
    # send HTTP request sequences to server and time responses
287
    $ro = $b2->execute;
288
    if ($short_print) {
289
        $short_ms.= "|".$b2->total_time."\n";
290
        $short_psec.="|".(int((1000*$b2->total_requests/$b2->total_time)*1000)/1000)."\n";
291
    } else {
292
        print ("\t".$b2->total_time."ms\t".(int((1000*$b2->total_requests/$b2->total_time)*1000)/1000)." borrowers/sec\n");
293
    }
294
} else {
295
    print "Skipping step 5\n";
296
}
297
298
#
299
# STEP 6: issue (& then return) books
300
#
301
if ($steps=~ /6/) {
302
    my $b3 = HTTPD::Bench::ApacheBench->new;
303
    $b3->concurrency( $concurrency );
304
    my $b4 = HTTPD::Bench::ApacheBench->new;
305
    $b4->concurrency( $concurrency );
306
307
    my @issues;
308
    my @returns;
309
    unless ($short_print) {
310
        print "Step 6a circulation (checkouts)        ";
311
    }
312
    $sth = $dbh->prepare("SELECT barcode FROM items WHERE itemnumber=?");
313
    my $sth2 = $dbh->prepare("SELECT borrowernumber FROM borrowers WHERE borrowernumber=?");
314
    for (my $i=1;$i<=$max_tries;$i++) {
315
        my $rand_borrowernumber;
316
        # check that the borrowernumber exist
317
        until ($rand_borrowernumber) {
318
            $rand_borrowernumber = int(rand($borrowernumber_max)+1);
319
            $sth2->execute($rand_borrowernumber);
320
            ($rand_borrowernumber) = $sth2->fetchrow;
321
        }
322
        # find a barcode & check it exists
323
        my $rand_barcode;
324
        until ($rand_barcode) {
325
            my $rand_itemnumber = int(rand($itemnumber_max)+1);
326
            $sth->execute($rand_itemnumber);
327
            ($rand_barcode) = $sth->fetchrow();
328
        }
329
        push @issues,"$baseurl/circ/circulation.pl?borrowernumber=$rand_borrowernumber&barcode=$rand_barcode&issueconfirmed=1";
330
        push @returns,"$baseurl/circ/returns.pl?barcode=$rand_barcode";
331
    }
332
    my $run3 = HTTPD::Bench::ApacheBench::Run->new
333
        ({ urls => \@issues,
334
           cookies => [$cookie],
335
        });
336
    $b3->add_run($run3);
337
    $b->add_run($run3);
338
339
    # send HTTP request sequences to server and time responses
340
    $ro = $b3->execute;
341
    # calculate hits/sec
342
    if ($short_print) {
343
        $short_ms.= "|".$b3->total_time."\n";
344
        $short_psec.="|".(int((1000*$b3->total_requests/$b3->total_time)*1000)/1000)."\n";
345
    } else {
346
        print ("\t".$b3->total_time."ms\t".(int((1000*$b3->total_requests/$b3->total_time)*1000)/1000)." checkouts/sec\n");
347
    }
348
    unless ($short_print) {
349
        print "Step 6b circulation (checkins)         ";
350
    }
351
    my $run4 = HTTPD::Bench::ApacheBench::Run->new
352
        ({ urls => \@returns,
353
           cookies => [$cookie],
354
        });
355
    $b4->add_run($run4);
356
    $b->add_run($run4);
357
358
    # send HTTP request sequences to server and time responses
359
    $ro = $b4->execute;
360
    # calculate hits/sec
361
    if ($short_print) {
362
        $short_ms.= "|".$b4->total_time."\n";
363
        $short_psec.="|".(int((1000*$b4->total_requests/$b4->total_time)*1000)/1000)."\n";
364
    } else {
365
        print ("\t".$b4->total_time."ms\t".(int((1000*$b4->total_requests/$b4->total_time)*1000)/1000)." checkins/sec\n");
366
    }
367
} else {
368
    print "Skipping step 6\n";
369
}
370
371
if ($steps=~ /0/) {
372
    unless ($short_print) {
373
        print "all transactions at once               ";
374
    }
375
    $ro = $b->execute;
376
    if ($short_print) {
377
        $short_ms.= "|".$b->total_time."\n";
378
        $short_psec.="|".(int((1000*$b->total_requests/$b->total_time)*1000)/1000)."\n";
379
    } else {
380
        print ("\t".$b->total_time."ms\t".(int((1000*$b->total_requests/$b->total_time)*1000)/1000)." operations/sec\n");
381
    }
382
} else {
383
    print "Skipping 'testing all transactions at once'\n (step 0)";
384
}
385
386
if ($short_print) {
387
print $short_ms."\n=====\n".$short_psec."\n";
388
}

Return to bug 6015