sbperf.pl 14.2 KB
Newer Older
Yadd's avatar
Yadd committed
1
#!/usr/bin/perl
Yadd's avatar
Yadd committed
2 3 4 5 6 7
#
# Session Backend Performance Test
# --------------------------------
#
# This test is used to compare different session backend. To use it, you have
# to:
Yadd's avatar
Yadd committed
8
#  * have a PostgreSQL database running on this host. PostgreSQL DB must:
Yadd's avatar
Yadd committed
9
#    * listen on 127.0.0.1:5432
Yadd's avatar
Yadd committed
10 11
#    * have a database names "sessions"
#    * have "hstore" extension enabled is database "sessions":
Yadd's avatar
Yadd committed
12
#        psql# CREATE EXTENSION hstore;
Yadd's avatar
Yadd committed
13 14 15 16 17 18
#    * have a Pg user named "sso" identified by "sso" password
#    * "sso" user must have right to create tables in database "sessions"
#  * have a MySQL or MriaDB database running on this host. DB must:
#    * listen on 127.0.0.1:3306
#    * have a database names "sessions"
#    * have a user named "sso" identified by "sso" password
Yadd's avatar
Yadd committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#    * "sso" user must have right to create tables in database "sessions"
#  * have a Redis server installed on this host listen on 127.0.0.1:6379
#
# If you want to enable LDAP test:
#  * set LLNGTESTLDAP environment variable to 1
#  * if OpenLDAP schemes aren't available in /etc/slapd/schema, set the scheme
#    directory in environment variables:
#      LLNGTESTLDAP_SCHEMA_DIR=/etc/ldap/schema
#  * prepare some coffee or tea
#  * open the window or light a fan
#  * launch the test, run away and come back 5mn later
#
#
# (c) Copyright: 2017, LemonLDAP::NG team
#
#This library is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2, or (at your option)
#any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see L<http://www.gnu.org/licenses/>.
Yadd's avatar
Yadd committed
46 47 48 49 50 51 52 53 54 55

use strict;
use DBI;
use JSON qw(from_json to_json);
use Time::HiRes;
use LWP::UserAgent;
use Redis;

system 'make stop_web_server';

56
eval { Redis->new->flushall };
Yadd's avatar
Yadd committed
57

Yadd's avatar
Yadd committed
58 59 60 61 62 63 64 65
my @legend = (
    'Apache::Session::Browseable::LDAP'        => 'LDAP',
    'Apache::Session::MySQL (no lock)'         => 'BMySQL',
    'Apache::Session::Browseable::MySQL'       => 'BiMySQL',
    'Apache::Session::Postgres (logged table)' => 'Postgres',
    'Apache::Session::Postgres'                => 'UPostgres',
    'Apache::Session::Browseable::Postgres'    => 'BPostgres',
    'Apache::Session::Browseable::PgJSON'      => 'PgJSON',
66
    'Apache::Session::Browseable::PgJSONB'     => 'PgJSONB',
Yadd's avatar
Yadd committed
67 68 69 70 71
    'Apache::Session::Browseable::PgHstore'    => 'PgHstore',
    'Apache::Session::Redis'                   => 'Redis',
    'Apache::Session::Browseable::Redis'       => 'BRedis',
);

Yadd's avatar
Yadd committed
72
my $tests = {
Yadd's avatar
Yadd committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    (
        $ENV{LLNGTESTLDAP}
        ? (
            LDAP => {
                cmd => 'cd lemonldap-ng-portal;perl t/test-ldap.pm;cd -',
                globalStorage        => 'Apache::Session::Browseable::LDAP',
                globalStorageOptions => {
                    ldapServer       => 'ldap://localhost:19389',
                    ldapBindDN       => 'cn=admin,dc=example,dc=com',
                    ldapBindPassword => 'admin',
                    ldapConfBase     => 'ou=sessions,dc=example,dc=com',
                    Index            => '_whatToTrace _session_kind'
                },
            }
          )
        : ()
    ),
Yadd's avatar
Yadd committed
90 91 92 93 94 95 96
    Redis => {
        globalStorage        => 'Apache::Session::Browseable::Redis',
        globalStorageOptions => {},
    },
    BRedis => {
        globalStorage        => 'Apache::Session::Browseable::Redis',
        globalStorageOptions => {
Yadd's avatar
Yadd committed
97
            Index => '_whatToTrace _session_kind'
Yadd's avatar
Yadd committed
98 99
        },
    },
Yadd's avatar
Yadd committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    BMySQL => {
        globalStorage        => 'Apache::Session::Browseable::MySQL',
        globalStorageOptions => {
            DataSource => 'dbi:mysql:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text)',
        ],
    },
    BiMySQL => {
        globalStorage        => 'Apache::Session::Browseable::MySQL',
        globalStorageOptions => {
            DataSource => 'dbi:mysql:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Index      => '_whatToTrace _session_kind _utime'
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text, _whatToTrace varchar(64), _session_kind varchar(15), _utime bigint)',
            'CREATE INDEX uid1 ON sessions (_whatToTrace) USING BTREE',
            'CREATE INDEX _s1 ON sessions (_session_kind) USING BTREE',
            'CREATE INDEX _u1 ON sessions (_utime) USING BTREE',
        ],
    },
Yadd's avatar
Yadd committed
128 129 130 131 132 133 134 135 136 137 138 139
    Postgres => {
        globalStorage        => 'Apache::Session::Browseable::Postgres',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
Yadd's avatar
Yadd committed
140
            'DROP INDEX IF EXISTS _u1',
Yadd's avatar
Yadd committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text)',
        ],
    },
    UPostgres => {
        globalStorage        => 'Apache::Session::Browseable::Postgres',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
Yadd's avatar
Yadd committed
156
            'DROP INDEX IF EXISTS _u1',
Yadd's avatar
Yadd committed
157 158 159 160 161 162 163 164 165 166
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session text)',
        ],
    },
    BPostgres => {
        globalStorage        => 'Apache::Session::Browseable::Postgres',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
Yadd's avatar
Yadd committed
167
            Index      => '_whatToTrace _session_kind _utime'
Yadd's avatar
Yadd committed
168 169 170 171 172
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
Yadd's avatar
Yadd committed
173
            'DROP INDEX IF EXISTS _u1',
Yadd's avatar
Yadd committed
174
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session text, _whatToTrace text, _session_kind text, _utime bigint)',
175
            'CREATE INDEX uid1 ON sessions USING BTREE (_whatToTrace text_pattern_ops)',
Yadd's avatar
Yadd committed
176
            'CREATE INDEX _s1 ON sessions (_session_kind)',
Yadd's avatar
Yadd committed
177
            'CREATE INDEX _u1 ON sessions (_utime)',
Yadd's avatar
Yadd committed
178 179
        ],
    },
Yadd's avatar
Yadd committed
180 181 182 183 184 185 186 187 188 189 190 191
    PgHstore => {
        globalStorage        => 'Apache::Session::Browseable::PgHstore',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
Yadd's avatar
Yadd committed
192
            'DROP INDEX IF EXISTS _u1',
Yadd's avatar
Yadd committed
193
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session hstore)',
194
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session -> '_whatToTrace') text_pattern_ops )",
Yadd's avatar
Yadd committed
195
            "CREATE INDEX _s1  ON sessions ( (a_session -> '_session_kind') )",
196
"CREATE INDEX _u1  ON sessions ( ( cast(a_session -> '_utime' AS bigint) ) )",
Yadd's avatar
Yadd committed
197 198
        ],
    },
Yadd's avatar
Yadd committed
199 200 201 202 203 204 205 206 207 208 209 210
    PgJSON => {
        globalStorage        => 'Apache::Session::Browseable::PgJSON',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
Yadd's avatar
Yadd committed
211
            'DROP INDEX IF EXISTS _u1',
Yadd's avatar
Yadd committed
212
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session json)',
213
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session ->> '_whatToTrace') text_pattern_ops )",
Yadd's avatar
Yadd committed
214
            "CREATE INDEX _s1  ON sessions ( (a_session ->> '_session_kind') )",
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
"CREATE INDEX _u1  ON sessions ( ( cast(a_session ->> '_utime' AS bigint) ) )",
        ],
    },
    PgJSONB => {
        globalStorage        => 'Apache::Session::Browseable::PgJSON',
        globalStorageOptions => {
            DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
            UserName   => 'sso',
            Password   => 'sso',
            Commit     => 1,
        },
        pg => [
            'DROP TABLE IF EXISTS sessions',
            'DROP INDEX IF EXISTS uid1',
            'DROP INDEX IF EXISTS _s1',
            'DROP INDEX IF EXISTS _u1',
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session jsonb)',
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session ->> '_whatToTrace') text_pattern_ops )",
            "CREATE INDEX _s1  ON sessions ( (a_session ->> '_session_kind') )",
"CREATE INDEX _u1  ON sessions ( ( cast(a_session ->> '_utime' AS bigint) ) )",
Yadd's avatar
Yadd committed
235 236 237 238 239 240 241 242
        ],
    },
};

my $times = {};

foreach my $name ( keys %$tests ) {
    my $opts = $tests->{$name}->{globalStorageOptions};
Yadd's avatar
Yadd committed
243 244 245 246
    if ( my $cmd = delete $tests->{$name}->{cmd} ) {
        system $cmd;
    }
    if ( my $cmd = delete $tests->{$name}->{pg} ) {
Yadd's avatar
Yadd committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
        my $dbh = DBI->connect( $opts->{DataSource}, $opts->{UserName},
            $opts->{Password}, { RaiseError => 1, AutoCommit => 1 } );
        foreach (@$cmd) {
            print STDERR "$_\n";
            $dbh->do($_);
        }
        $dbh->disconnect;
    }
    system 'make start_web_server';
    print STDERR "Removing manager protection\n";
    system
q(perl -i -pe 's/protection\s*=\s*manager/protection=none/' e2e-tests/conf/lemonldap-ng.ini);
    print STDERR "Read conf\n";
    open F, 'e2e-tests/conf/lmConf-1.json' or die;
    my $conf = join '', <F>;
    close F;
    $conf = from_json($conf);

    foreach my $k ( keys %{ $tests->{$name} } ) {
        $conf->{$k} = $tests->{$name}->{$k};
    }
Yadd's avatar
Yadd committed
268 269 270

    # Fix timeout to 2h
    $conf->{timeout} = 7200;
Yadd's avatar
Yadd committed
271 272 273 274
    print STDERR "Write conf\n";
    open F, '>e2e-tests/conf/lmConf-1.json' or die;
    print F to_json($conf);
    close F;
Yadd's avatar
Yadd committed
275

Yadd's avatar
Yadd committed
276 277 278 279
    #system 'cat e2e-tests/conf/lmConf-1.json';
    sleep(1);
    system 'make reload_web_server';

Yadd's avatar
Yadd committed
280
    # Insert 1000 sessions
Yadd's avatar
Yadd committed
281 282 283 284
    my $t = Time::HiRes::time();
    system './e2e-tests/populate.pl';
    $times->{$name}->{insert} = Time::HiRes::time() - $t;

Yadd's avatar
Yadd committed
285
    # Initialize manager
Yadd's avatar
Yadd committed
286 287
    my $ua = LWP::UserAgent->new;
    $ua->get('http://manager.example.com:19876/sessions.html');
Yadd's avatar
Yadd committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301

    my $tmp = {
        read       => 0,
        getLetter  => 0,
        getUid     => 0,
        getSession => 0,
    };

    # First loop isn't used in averages
    foreach my $i ( 0 .. 10 ) {

        # Test first Session Explorer access
        $t = Time::HiRes::time();
        my $res = $ua->get(
Yadd's avatar
Yadd committed
302
'http://manager.example.com:19876/manager.fcgi/sessions/global?groupBy=substr(_whatToTrace,1)'
Yadd's avatar
Yadd committed
303 304 305 306 307 308 309 310
        );
        $tmp->{read} += Time::HiRes::time() - $t if ($i);
        $res = from_json( $res->content );

        # Partial "_whatToTrace" search
        my $letter = $res->{values}->[0]->{value};
        $t   = Time::HiRes::time();
        $res = $ua->get(
Yadd's avatar
Yadd committed
311
'http://manager.example.com:19876/manager.fcgi/sessions/global?_whatToTrace='
Yadd's avatar
Yadd committed
312 313 314 315 316 317 318 319 320
              . $letter
              . '*&groupBy=_whatToTrace' );
        $tmp->{getLetter} += Time::HiRes::time() - $t if ($i);
        $res = from_json( $res->content );

        # Search for an uid
        my $user = $res->{values}->[$i]->{value};
        $t   = Time::HiRes::time();
        $res = $ua->get(
Yadd's avatar
Yadd committed
321
'http://manager.example.com:19876/manager.fcgi/sessions/global?_whatToTrace='
Yadd's avatar
Yadd committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
              . $user );
        $tmp->{getUid} += Time::HiRes::time() - $t if ($i);
        $res = from_json( $res->content );

        # Get a session
        my $id = $res->{values}->[0]->{session};
        $t   = Time::HiRes::time();
        $res = $ua->get(
            'http://manager.example.com:19876/manager.fcgi/sessions/global/'
              . $id );
        $tmp->{getSession} += Time::HiRes::time() - $t if ($i);
        $res = from_json( $res->content );
    }

    # Average
    foreach my $type ( keys %$tmp ) {
        $times->{$name}->{$type} = $tmp->{$type} / 10;
    }

    # Purge half sessions
    $t = Time::HiRes::time();
    system 'LLNG_DEFAULTCONFFILE=e2e-tests/conf/lemonldap-ng.ini '
      . 'perl -Ilemonldap-ng-common/blib/lib '
      . 'lemonldap-ng-portal/site/cron/purgeCentralCache';
    $times->{$name}->{purge} = Time::HiRes::time() - $t;

    # Turn off webserver
Yadd's avatar
Yadd committed
349 350 351
    system 'make stop_web_server';
}

Yadd's avatar
Yadd committed
352
if ( $ENV{LLNGTESTLDAP} ) {
Yadd's avatar
Yadd committed
353 354 355 356
    if ( open F, 'lemonldap-ng-portal/t/testslapd/slapd.pid' ) {
        my $pid = join '', <F>;
        system "kill $pid";
    }
Yadd's avatar
Yadd committed
357 358 359 360
    system 'rm -rf lemonldap-ng-portal/t/testslapd/slapd.d';
    system 'rm -rf lemonldap-ng-portal/t/testslapd/data';
    system 'rm -rf lemonldap-ng-portal/t/testslapd/slapd-test.ldif';
}
Yadd's avatar
Yadd committed
361 362 363 364 365

#use Data::Dumper;
#print Dumper($times);

print <<EOT;
Yadd's avatar
Yadd committed
366 367 368 369
+-----------------------------------------+-------------------------------------+-----------------------------------+
|                                         |              Main use               |          Session explorer         |
|                 Backend                 | Insert 1000 |   Get 1   | Purge 500 | Parse all |  1 letter |   1 user  |
+-----------------------------------------+-------------------------------------+-----------------------------------+
Yadd's avatar
Yadd committed
370
EOT
Yadd's avatar
Yadd committed
371 372 373 374 375
for ( my $i = 0 ; $i < @legend ; $i += 2 ) {
    my $type = $legend[ $i + 1 ];
    next unless ( $times->{$type} );
    printf "|%40s |%11.5f  |  %.5f  |  %7.4f  |  %.5f  |  %.5f  |  %.5f  |\n",
      $legend[$i],
Yadd's avatar
Yadd committed
376 377
      map { $times->{$type}->{$_} }
      qw(insert getSession purge read getLetter getUid);
Yadd's avatar
Yadd committed
378
}
Yadd's avatar
Yadd committed
379
print
Yadd's avatar
Yadd committed
380
"+-----------------------------------------+-------------------------------------+-----------------------------------+\n";