fastcgi performance problems and ruby


A

andrew.stuart

Hello

I have recently embarked upon the process of getting FastCGI to work
with Apache in order to run Ruby via FastCGI.

It is all working a running but the performance is not what I had
expected and certainly not what is needed to run a production web
application.

Strange because I am using fairly powerful computers. Stranger because
this discussion thread

http://groups.google.com/[email protected]&rnum=9&p
rev=/groups%3Fnum%3D100%26hl%3Den%26lr%3Dlang_en%26safe%3Doff%26q%3Dfastcgi%2Bruby%26btnG%3DSearch

-->extract from above thread
a) 400 request/sec with mod_ruby and cached Ruby script
b) 200 request/sec with fastcgi.so (the mixed C/Ruby version)
c) 100 request/sec with FCGI (clean Ruby version)
d) 70 request/sec with mod_ruby naive.


The thread above seems to suggest that it would be reasonable to expect
at least 200 requests/second using

fastcgi. I actually would have expected better performance than this
because I am using a 2.4ghz p4

I have included results of my tests below.

Can anyone throw any light for me on what sort performance I should
expect from ruby under mod_fastcgi?

Would anyone mind taking the trouble to benchmark their own mod_fastcgi
performance with Ruby?

I'm concerned that unless I get the performance up then ruby with
fastcgi does not represent a production

level solution from a performance perspective.

Thanks in advance for any help.

Andrew Stuart
andrew dot stuart at xse dot com dot au

***********************************************************************
***********************************************************************
****************load testing application
http://www.acme.com/software/http_load/
http_load - multiprocessing http test client

load testing executed on the web server itself. not from a client over
the network

***********************************************************************
***********************************************************************
****************server config
Intel P4 Celeron 2.4Ghz
512meg RAM
Fedora core 2
Apache
FastGCI
Ruby
Postgres

***********************************************************************
***********************************************************************
****************output of "free" shows plenty of memory available on
server

[[email protected] docs]# free
total used free shared buffers
cached
Mem: 483724 138532 345192 0 21532
47944
-/+ buffers/cache: 69056 414668
Swap: 979956 0 979956
[[email protected] docs]#

***********************************************************************
***********************************************************************
****************performance test plain HTML file -- 897.629 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82testhtml.txt
17960 fetches, 20 max parallel, 1.42082e+08 bytes, in 20.0083 seconds
7911 mean bytes/connection
897.629 fetches/sec, 7.10114e+06 bytes/sec
msecs/connect: 2.19892 mean, 20.245 max, 0.133 min
msecs/first-response: 11.1338 mean, 20.245 max, 9.666 min
HTTP response codes:
code 200 -- 17960
[[email protected] http_load-04jan2002]#

***********************************************************************
***********************************************************************
****************performance test FastCGI simple ruby script dump env --
155.699 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 urlfcgienvrb.txt
3114 fetches, 100 max parallel, 2.21717e+06 bytes, in 20.0001 seconds
712 mean bytes/connection
155.699 fetches/sec, 110858 bytes/sec
msecs/connect: 0.445062 mean, 30.947 max, 0.152 min
msecs/first-response: 630.785 mean, 883.717 max, 13.366 min
HTTP response codes:
code 200 -- 3114
[[email protected] http_load-04jan2002]#

Ruby script source for this test:

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/env.rb
#!/usr/bin/ruby
require 'cgi'
require 'fcgi'


FCGI.each_cgi do |cgi|
content = ''
env = []
cgi.env_table.each do |k,v|
env << [k,v]
end
env.sort!
env.each do |k,v|
content << %Q(#{k} => #{v}<br>\n)
end
content << "hello from dude"
cgi.out{content}
end

[[email protected] http_load-04jan2002]#

***********************************************************************
***********************************************************************
****************performance test FastCGI database access ruby script --
35.9997 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82dbtestrb.txt
1639 fetches, 100 max parallel, 908006 bytes, in 20.0001 seconds
554 mean bytes/connection
81.9498 fetches/sec, 45400.2 bytes/sec
msecs/connect: 0.429315 mean, 20.021 max, 0.146 min
msecs/first-response: 1182.09 mean, 1489.77 max, 208.131 min
HTTP response codes:
code 200 -- 1639
[[email protected] http_load-04jan2002]#

Ruby script source for this test:

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/dbtest.rb
#!/usr/bin/ruby
require 'cgi'
require 'fcgi'
require 'dbi'

dbh = DBI.connect('DBI:pg:catchmail', 'dbusername', 'password')

FCGI.each_cgi do |cgi|

content = ''
dbh.select_all('select msgno, msgtype, msgsubject, msgbody from
message limit 10 offset 50') do |row|
content << "subject line: "
content << row["msgsubject"]
content << "<br>"
end

cgi.out{content}
end

dbh.disconnect
[[email protected] http_load-04jan2002]#


***********************************************************************
***********************************************************************
****************performance test FastCGI echo example -- 664.188
fetches/sec


[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82fcgiecho.txt
13290 fetches, 31 max parallel, 1.21736e+07 bytes, in 20.0094 seconds
916 mean bytes/connection
664.188 fetches/sec, 608396 bytes/sec
msecs/connect: 2.56759 mean, 30.368 max, 0.153 min
msecs/first-response: 15.0369 mean, 86.158 max, 12.604 min
HTTP response codes:
code 200 -- 13290
[[email protected] http_load-04jan2002]#

Source code for echo is written in C and is included in the examples in
the fastcgi software


***********************************************************************
***********************************************************************
****************performance test PHP example (not using FastCGI) --
234.798 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82testphp.txt
4699 fetches, 100 max parallel, 1.88669e+08 bytes, in 20.013 seconds
40150.9 mean bytes/connection
234.798 fetches/sec, 9.42734e+06 bytes/sec
msecs/connect: 5.28116 mean, 113.121 max, 0.15 min
msecs/first-response: 161.609 mean, 2363 max, 22.176 min
HTTP response codes:
code 200 -- 4699
[[email protected] http_load-04jan2002]#


Source code for test.php

[[email protected] html]# cat test.php
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php echo '<p>Hello World</p>'; ?>
</body>
</html>

<?php
phpinfo();
?>

***********************************************************************
***********************************************************************
****************performance test FastCGI simple ruby script dump
username/IP -- 159.399 fetches/sec

[[email protected] html]#
[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 urlfcgiusernamerb.txt
3188 fetches, 100 max parallel, 153024 bytes, in 20.0001 seconds
48 mean bytes/connection
159.399 fetches/sec, 7651.15 bytes/sec
msecs/connect: 0.462713 mean, 41.912 max, 0.168 min
msecs/first-response: 615.345 mean, 949.505 max, 160.687 min
HTTP response codes:
code 200 -- 3188
[[email protected] http_load-04jan2002]#

Source code for username.rb

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/username.rb
#!/usr/bin/ruby

require "fcgi"

FCGI.each_cgi {|cgi|
puts cgi.header
puts "You are #{cgi.remote_user} <br>"
puts "Connecting from #{cgi.remote_addr} <br>"
}

[[email protected] http_load-04jan2002]#


***********************************************************************
***********************************************************************
***************************extract from httpd.conf relating to FastCGI

LoadModule fastcgi_module modules/mod_fastcgi.so

<IfModule mod_fastcgi.c>

# URIs that begin with /fcgi-bin/, are found in /var/www/fcgi-bin/
Alias /fcgi-bin/ /var/www/fcgi-bin/

FastCgiIpcDir /var/fcgi/
#FastCgiConfig -autoUpdate

# Anything in here is handled as a "dynamic" server if not defined
as "static" or "external"
<Directory /var/www/fcgi-bin/>
Order allow,deny
Allow from all
SetHandler fastcgi-script
Options +ExecCGI
#Require user andrewstuart
</Directory>

# Anything with one of these extensions is handled as a "dynamic"
server if not defined as
# "static" or "external". Note: "dynamic" servers require ExecCGI
to be on in their directory.
AddHandler fastcgi-script .fcgi .fpl

# Start a "static" server at httpd initialization inside the scope
of the SetHandler
FastCgiServer /var/www/fcgi-bin/examples/echo -processes 5

# Start a "static" server at httpd initialization inside the scope
of the AddHandler
#FastCgiServer /var/www/fcgi-bin/examples/echo

# Start a "static" server at httpd initialization outside the scope
of the Set/AddHandler
#FastCgiServer /var/www/htdocs/some/path/coolapp
<Directory /var/www/html/ruby>
SetHandler fastcgi-script
</Directory>

</IfModule>
 
Ad

Advertisements

A

Ara.T.Howard

Can anyone throw any light for me on what sort performance I should
expect from ruby under mod_fastcgi?

i can't run all of them - but here's the env test:


[[email protected] htdocs]$ cat env.fcgi
#!/usr/local/ruby-1.8.0/bin/ruby
require 'cgi'
require 'fcgi'
FCGI.each_cgi do |cgi|
content = ''
env = []
cgi.env_table.each{|k,v| env << [k,v]}
env.sort!
env.each{|k,v| content << %Q(#{k} => #{v}<br>\n)}
cgi.out{content}
end




[[email protected] htdocs]$ echo http://127.0.0.1/env.fcgi | http_load -verbose -parallel 100 -seconds 20 /dev/stdin
4420 fetches, 100 max parallel, 3.54926e+06 bytes, in 20.0237 seconds
803 mean bytes/connection
220.738 fetches/sec, 177253 bytes/sec
msecs/connect: 5.67523 mean, 127.545 max, 0.203 min
msecs/first-response: 86.2776 mean, 1077.36 max, 29.886 min
HTTP response codes:
code 200 -- 4420




[[email protected] htdocs]$ ab -n 100 -c 100 -t 20 http://127.0.0.1/env.fcgi
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.116 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Finished 4129 requests


Server Software: Apache/2.0.47
Server Hostname: 127.0.0.1
Server Port: 80

Document Path: /env.fcgi
Document Length: 829 bytes

Concurrency Level: 100
Time taken for tests: 20.365556 seconds
Complete requests: 4129
Failed requests: 0
Write errors: 0
Total transferred: 4244612 bytes
HTML transferred: 3422941 bytes
Requests per second: 202.74 [#/sec] (mean)
Time per request: 493.232 [ms] (mean)
Time per request: 4.932 [ms] (mean, across all concurrent requests)
Transfer rate: 203.53 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.6 0 92
Processing: 71 483 105.3 468 1689
Waiting: 2 312 158.4 344 1299
Total: 71 483 105.3 468 1689

Percentage of the requests served within a certain time (ms)
50% 468
66% 490
75% 493
80% 495
90% 544
95% 657
98% 802
99% 879
100% 1689 (longest request)



my machine info (it's a dog)


[[email protected] htdocs]$ uname -srm
Linux 2.4.20-8 i686


[[email protected] htdocs]$ cat /etc/redhat-release
Red Hat Linux release 9 (Shrike)
[[email protected] htdocs]$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 5
model name : Pentium II (Deschutes)
stepping : 2
cpu MHz : 398.273
cache size : 512 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat pse36 mmx fxsr
bogomips : 794.62


[[email protected] htdocs]$ cat /proc/meminfo
total: used: free: shared: buffers: cached:
Mem: 393760768 364519424 29241344 0 80605184 192499712
Swap: 263200768 11534336 251666432
MemTotal: 384532 kB
MemFree: 28556 kB
MemShared: 0 kB
Buffers: 78716 kB
Cached: 176740 kB
SwapCached: 11248 kB
Active: 241496 kB
ActiveAnon: 40960 kB
ActiveCache: 200536 kB
Inact_dirty: 100 kB
Inact_laundry: 57860 kB
Inact_clean: 5604 kB
Inact_target: 61012 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 384532 kB
LowFree: 28556 kB
SwapTotal: 257032 kB
SwapFree: 245768 kB
[[email protected] htdocs]$ ruby -v
ruby 1.8.0 (2003-09-22) [i686-linux]
[[email protected] htdocs]$ httpd -v
Server version: Apache/2.0.40
Server built: Feb 25 2003 05:01:56



hope that's helpful.


kind regards.



-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| When you do something, you should burn yourself completely, like a good
| bonfire, leaving no trace of yourself. --Shunryu Suzuki
===============================================================================
 
J

J. D.

Hello

I have recently embarked upon the process of getting FastCGI to work
with Apache in order to run Ruby via FastCGI.

It is all working a running but the performance is not what I had
expected and certainly not what is needed to run a production web
application.

Strange because I am using fairly powerful computers. Stranger because
this discussion thread

http://groups.google.com/[email protected]&rnum=9&p
rev=/groups%3Fnum%3D100%26hl%3Den%26lr%3Dlang_en%26safe%3Doff%26q%3Dfastcgi%2Bruby%26btnG%3DSearch

-->extract from above thread
a) 400 request/sec with mod_ruby and cached Ruby script
b) 200 request/sec with fastcgi.so (the mixed C/Ruby version)
c) 100 request/sec with FCGI (clean Ruby version)
d) 70 request/sec with mod_ruby naive.


The thread above seems to suggest that it would be reasonable to expect
at least 200 requests/second using

fastcgi. I actually would have expected better performance than this
because I am using a 2.4ghz p4

I have included results of my tests below.

Can anyone throw any light for me on what sort performance I should
expect from ruby under mod_fastcgi?

Would anyone mind taking the trouble to benchmark their own mod_fastcgi
performance with Ruby?

I'm concerned that unless I get the performance up then ruby with
fastcgi does not represent a production

level solution from a performance perspective.

Thanks in advance for any help.

Andrew Stuart
andrew dot stuart at xse dot com dot au

***********************************************************************
***********************************************************************
****************load testing application
http://www.acme.com/software/http_load/
http_load - multiprocessing http test client

load testing executed on the web server itself. not from a client over
the network

***********************************************************************
***********************************************************************
****************server config
Intel P4 Celeron 2.4Ghz
512meg RAM
Fedora core 2
Apache
FastGCI
Ruby
Postgres

***********************************************************************
***********************************************************************
****************output of "free" shows plenty of memory available on
server

[[email protected] docs]# free
total used free shared buffers
cached
Mem: 483724 138532 345192 0 21532
47944
-/+ buffers/cache: 69056 414668
Swap: 979956 0 979956
[[email protected] docs]#

***********************************************************************
***********************************************************************
****************performance test plain HTML file -- 897.629 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82testhtml.txt
17960 fetches, 20 max parallel, 1.42082e+08 bytes, in 20.0083 seconds
7911 mean bytes/connection
897.629 fetches/sec, 7.10114e+06 bytes/sec
msecs/connect: 2.19892 mean, 20.245 max, 0.133 min
msecs/first-response: 11.1338 mean, 20.245 max, 9.666 min
HTTP response codes:
code 200 -- 17960
[[email protected] http_load-04jan2002]#

***********************************************************************
***********************************************************************
****************performance test FastCGI simple ruby script dump env --
155.699 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 urlfcgienvrb.txt
3114 fetches, 100 max parallel, 2.21717e+06 bytes, in 20.0001 seconds
712 mean bytes/connection
155.699 fetches/sec, 110858 bytes/sec
msecs/connect: 0.445062 mean, 30.947 max, 0.152 min
msecs/first-response: 630.785 mean, 883.717 max, 13.366 min
HTTP response codes:
code 200 -- 3114
[[email protected] http_load-04jan2002]#

Ruby script source for this test:

[[email protected]ecore http_load-04jan2002]# cat /var/www/fcgi-bin/env.rb
#!/usr/bin/ruby
require 'cgi'
require 'fcgi'


FCGI.each_cgi do |cgi|
content = ''
env = []
cgi.env_table.each do |k,v|
env << [k,v]
end
env.sort!
env.each do |k,v|
content << %Q(#{k} => #{v}<br>\n)
end
content << "hello from dude"
cgi.out{content}
end

[[email protected] http_load-04jan2002]#

***********************************************************************
***********************************************************************
****************performance test FastCGI database access ruby script --
35.9997 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82dbtestrb.txt
1639 fetches, 100 max parallel, 908006 bytes, in 20.0001 seconds
554 mean bytes/connection
81.9498 fetches/sec, 45400.2 bytes/sec
msecs/connect: 0.429315 mean, 20.021 max, 0.146 min
msecs/first-response: 1182.09 mean, 1489.77 max, 208.131 min
HTTP response codes:
code 200 -- 1639
[[email protected] http_load-04jan2002]#

Ruby script source for this test:

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/dbtest.rb
#!/usr/bin/ruby
require 'cgi'
require 'fcgi'
require 'dbi'

dbh = DBI.connect('DBI:pg:catchmail', 'dbusername', 'password')

FCGI.each_cgi do |cgi|

content = ''
dbh.select_all('select msgno, msgtype, msgsubject, msgbody from
message limit 10 offset 50') do |row|
content << "subject line: "
content << row["msgsubject"]
content << "<br>"
end

cgi.out{content}
end

dbh.disconnect
[[email protected] http_load-04jan2002]#


***********************************************************************
***********************************************************************
****************performance test FastCGI echo example -- 664.188
fetches/sec


[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82fcgiecho.txt
13290 fetches, 31 max parallel, 1.21736e+07 bytes, in 20.0094 seconds
916 mean bytes/connection
664.188 fetches/sec, 608396 bytes/sec
msecs/connect: 2.56759 mean, 30.368 max, 0.153 min
msecs/first-response: 15.0369 mean, 86.158 max, 12.604 min
HTTP response codes:
code 200 -- 13290
[[email protected] http_load-04jan2002]#

Source code for echo is written in C and is included in the examples in
the fastcgi software


***********************************************************************
***********************************************************************
****************performance test PHP example (not using FastCGI) --
234.798 fetches/sec

[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 url82testphp.txt
4699 fetches, 100 max parallel, 1.88669e+08 bytes, in 20.013 seconds
40150.9 mean bytes/connection
234.798 fetches/sec, 9.42734e+06 bytes/sec
msecs/connect: 5.28116 mean, 113.121 max, 0.15 min
msecs/first-response: 161.609 mean, 2363 max, 22.176 min
HTTP response codes:
code 200 -- 4699
[[email protected] http_load-04jan2002]#


Source code for test.php

[[email protected] html]# cat test.php
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php echo '<p>Hello World</p>'; ?>
</body>
</html>

<?php
phpinfo();
?>

***********************************************************************
***********************************************************************
****************performance test FastCGI simple ruby script dump
username/IP -- 159.399 fetches/sec

[[email protected] html]#
[[email protected] http_load-04jan2002]# ./http_load -verbose -parallel 100
-seconds 20 urlfcgiusernamerb.txt
3188 fetches, 100 max parallel, 153024 bytes, in 20.0001 seconds
48 mean bytes/connection
159.399 fetches/sec, 7651.15 bytes/sec
msecs/connect: 0.462713 mean, 41.912 max, 0.168 min
msecs/first-response: 615.345 mean, 949.505 max, 160.687 min
HTTP response codes:
code 200 -- 3188
[[email protected] http_load-04jan2002]#

Source code for username.rb

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/username.rb
#!/usr/bin/ruby

require "fcgi"

FCGI.each_cgi {|cgi|
puts cgi.header
puts "You are #{cgi.remote_user} <br>"
puts "Connecting from #{cgi.remote_addr} <br>"
}

[[email protected] http_load-04jan2002]#


***********************************************************************
***********************************************************************
***************************extract from httpd.conf relating to FastCGI

LoadModule fastcgi_module modules/mod_fastcgi.so

<IfModule mod_fastcgi.c>

# URIs that begin with /fcgi-bin/, are found in /var/www/fcgi-bin/
Alias /fcgi-bin/ /var/www/fcgi-bin/

FastCgiIpcDir /var/fcgi/
#FastCgiConfig -autoUpdate

# Anything in here is handled as a "dynamic" server if not defined
as "static" or "external"
<Directory /var/www/fcgi-bin/>
Order allow,deny
Allow from all
SetHandler fastcgi-script
Options +ExecCGI
#Require user andrewstuart
</Directory>

# Anything with one of these extensions is handled as a "dynamic"
server if not defined as
# "static" or "external". Note: "dynamic" servers require ExecCGI
to be on in their directory.
AddHandler fastcgi-script .fcgi .fpl

# Start a "static" server at httpd initialization inside the scope
of the SetHandler
FastCgiServer /var/www/fcgi-bin/examples/echo -processes 5

# Start a "static" server at httpd initialization inside the scope
of the AddHandler
#FastCgiServer /var/www/fcgi-bin/examples/echo

# Start a "static" server at httpd initialization outside the scope
of the Set/AddHandler
#FastCgiServer /var/www/htdocs/some/path/coolapp
<Directory /var/www/html/ruby>
SetHandler fastcgi-script
</Directory>

</IfModule>

Sometimes, limiting the number of fastcgi processes that get created can
help boost performance. See:

http://www.renegadeinternet.com/kb/faq.php?num=4&f_id=11&s_id=34&q_id=125
 
Z

Zev Blut

Hello,

Ruby script source for this test:

[[email protected] http_load-04jan2002]# cat /var/www/fcgi-bin/env.rb
#!/usr/bin/ruby
require 'cgi'
require 'fcgi'


FCGI.each_cgi do |cgi|
content = ''
env = []
cgi.env_table.each do |k,v|
env << [k,v]
end
env.sort!
env.each do |k,v|
content << %Q(#{k} => #{v}<br>\n)
end
content << "hello from dude"
cgi.out{content}
end

Note, that the FCGI.each_cgi method is slower than the FCGI.each method.
Depending upon how you want to use FCGI with a CGI object this may or may
not be necessary.
You may want to try the following code snippet to see if there is
any significant difference between FCGI.each_cgi and FCGI.each.

#!/usr/bin/ruby
require "fcgi"
FCGI.each do |request|
out = request.out
content = ""
env = Array.new
request.env.each do |k,v|
env << [k,v]
end
env.sort!
env.each do |k,v|
content << %Q(#{k} => #{v}<br>\n)
end

content << "hello from dude"
out.print "Content-Type: text/plain\r\n"
out.print "Content-Length: #{content.size}\r\n"
out.print "\r\n"
out.print content
request.finish
end


Best,
Zev
 
P

Patrick May

Hello,

Note, that the FCGI.each_cgi method is slower than the FCGI.each
method.
Depending upon how you want to use FCGI with a CGI object this may or
may
not be necessary.
You may want to try the following code snippet to see if there is
any significant difference between FCGI.each_cgi and FCGI.each.

It would make sense for each_cgi to be slower. I think CGI adds alot
of methods to itself dynamically on initialization.

~ pat
 
G

gabriele renzi

J. D. ha scritto:

a little suggestion: try to quote a little less if the quote is not
necessary :)

(sorry if I sound rude, not being a native speaker, I sometime do)
 
Ad

Advertisements

B

Brian Candler

cgi.out{content}

I think that may be your problem. The 'out' methods of cgi are inefficient,
I believe due to the large number of singleton methods which are added on
each object - although I seem to remember it's much worse if you do
each_cgi("html3") for example.

As suggested elsewhere, try rewriting your app to use the native fastcgi API
(each) rather than each_cgi.

Also, if your benchmarks are forcing a lot of concurrent connections, then
you could try configuring mod_fastcgi to launch a static pool of processes
for your application (say 5 or 10 processes) to see if that zips things
along, because in that case they will be pre-spawned.

Regards,

Brian.
 
T

trans. (T. Onoma)

On Tuesday 02 November 2004 06:20 am, Brian Candler wrote:
| > cgi.out{content}
|
| I think that may be your problem. The 'out' methods of cgi are inefficient,
| I believe due to the large number of singleton methods which are added on
| each object - although I seem to remember it's much worse if you do
| each_cgi("html3") for example.
|
| As suggested elsewhere, try rewriting your app to use the native fastcgi
| API (each) rather than each_cgi.
|
| Also, if your benchmarks are forcing a lot of concurrent connections, then
| you could try configuring mod_fastcgi to launch a static pool of processes
| for your application (say 5 or 10 processes) to see if that zips things
| along, because in that case they will be pre-spawned.

I'm also curious about Singleton Class, i.e. I recall (it was a while ago)
somthing about modifying CGI to be a Singleton class rather then a regular
class --that seemed helpful. I wonder if that would help and/or if the same
can be applied to FCGI. But I'm not sure how that all fits together so I was
wondering if someone could make sense it for us.

Thanks,
T.
 
B

Brian Candler

I'm also curious about Singleton Class, i.e. I recall (it was a while ago)
somthing about modifying CGI to be a Singleton class rather then a regular
class --that seemed helpful.

That sentence doesn't make much sense to me - can you define what you mean
by "modifying .. to be a Singleton class rather than a regular class" ??

Remember that:

1. CGI is_a Class (i.e. CGI is an object, an instance of class Class)

2. This object has a singleton class; that is, methods which apply to
CGI itself, and not to any instance of class CGI, nor any other
instance of class Class.

For example, CGI.escapeHTML is a method within CGI's singleton class

3. Singleton classes are anonymous; there is no need to name them, as they
are always only associated with one object.

So I can't really make sense of what you're suggesting. If you've not seen
it, have a look at http://www.rubygarden.org/ruby?SingletonTutorial and see
if that makes the terminology any clearer.

The issue with performance is: CGI.new creates a new object (an instance of
class CGI), and at object creation time, a whole bunch of methods are added
at run-time to that instance's singleton class.

e.g.

a = CGI.new("html3")
b = CGI.new("html4")

creates two objects, each of which is an instance of CGI, but if you look in
the source for cgi.rb you can see a lot of work is done in the initialize()
method:

case type
when "html3"
extend Html3
element_init()
extend HtmlExtension
when "html4"
extend Html4
element_init()
extend HtmlExtension

In turn, method element_init does a whole load of work defining methods the
slow way, with code such as

for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
CAPTION ]
methods += <<-BEGIN + nn_element_def(element) + <<-END
def #{element.downcase}(attributes = {})
BEGIN
end
END
end
...
eval(methods)

I'm sure this was to save the programmer having to enumerate all these
methods in the mixin, but I'd have thought it could be done more
efficiently than that (by defining the methods once in the mixin, not at
run-time in every object instance)

Perhaps the assumption in the CGI library is that normally a CGI is a
one-shot process: there is no point carefully preparing mixins for
Html3/Html4/Html4Tr/Html4Fr if at runtime only one will be used and then the
CGI will terminate. But that assumption is not true for a FastCGI
environment.

But actually, if you just use CGI.new without passing a html type, this
heavyweight construction work isn't done anyway.

Regards,

Brian.
 
T

trans. (T. Onoma)

29:09PM +0900, trans. (T. Onoma) wrote:
| > I'm also curious about Singleton Class, i.e. I recall (it was a while
| > ago) somthing about modifying CGI to be a Singleton class rather then a
| > regular class --that seemed helpful.
|
| That sentence doesn't make much sense to me - can you define what you mean
| by "modifying .. to be a Singleton class rather than a regular class" ??

Ah yes, the old name confusion. Sorry. I'm _not_ referring to Virtual class
(or Instance class), which is also called singleton. That's different. (BTW
we really need to get onto this new naming convention to prevent this
confusion! Yes?) I'm referring to the other kind where by only one instance
of a class can exist. See Singleton module for more info on that.

So if I make CGI singleton, then only one instance of it ever exists
--presumably even between http requests. Thus an increase in performance. But
like I said I'm not perfectly clear about how it all works, and how FCGI
might fit in.

HTH,
T.


| Remember that:
|
| 1. CGI is_a Class (i.e. CGI is an object, an instance of class Class)
|
| 2. This object has a singleton class; that is, methods which apply to
| CGI itself, and not to any instance of class CGI, nor any other
| instance of class Class.
|
| For example, CGI.escapeHTML is a method within CGI's singleton class
|
| 3. Singleton classes are anonymous; there is no need to name them, as they
| are always only associated with one object.
|
| So I can't really make sense of what you're suggesting. If you've not seen
| it, have a look at http://www.rubygarden.org/ruby?SingletonTutorial and see
| if that makes the terminology any clearer.
|
| The issue with performance is: CGI.new creates a new object (an instance of
| class CGI), and at object creation time, a whole bunch of methods are added
| at run-time to that instance's singleton class.
|
| e.g.
|
| a = CGI.new("html3")
| b = CGI.new("html4")
|
| creates two objects, each of which is an instance of CGI, but if you look
| in the source for cgi.rb you can see a lot of work is done in the
| initialize() method:
|
| case type
| when "html3"
| extend Html3
| element_init()
| extend HtmlExtension
| when "html4"
| extend Html4
| element_init()
| extend HtmlExtension
|
| In turn, method element_init does a whole load of work defining methods the
| slow way, with code such as
|
| for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
| DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
| APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
| STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
| CAPTION ]
| methods += <<-BEGIN + nn_element_def(element) + <<-END
| def #{element.downcase}(attributes = {})
| BEGIN
| end
| END
| end
| ...
| eval(methods)
|
| I'm sure this was to save the programmer having to enumerate all these
| methods in the mixin, but I'd have thought it could be done more
| efficiently than that (by defining the methods once in the mixin, not at
| run-time in every object instance)
|
| Perhaps the assumption in the CGI library is that normally a CGI is a
| one-shot process: there is no point carefully preparing mixins for
| Html3/Html4/Html4Tr/Html4Fr if at runtime only one will be used and then
| the CGI will terminate. But that assumption is not true for a FastCGI
| environment.
|
| But actually, if you just use CGI.new without passing a html type, this
| heavyweight construction work isn't done anyway.
|
| Regards,
|
| Brian.
 
B

Brian Candler

| That sentence doesn't make much sense to me - can you define what you mean
| by "modifying .. to be a Singleton class rather than a regular class" ??

Ah yes, the old name confusion. Sorry. I'm _not_ referring to Virtual class
(or Instance class), which is also called singleton. That's different. (BTW
we really need to get onto this new naming convention to prevent this
confusion! Yes?) I'm referring to the other kind where by only one instance
of a class can exist. See Singleton module for more info on that.

OK, the 'Singleton pattern'. Always seemed rather pointless to me; if
there's only ever going to be one CGI instance, then you might as well make
all the methods class methods of CGI itself, and use class instance
variables.
So if I make CGI singleton, then only one instance of it ever exists
--presumably even between http requests. Thus an increase in performance. But
like I said I'm not perfectly clear about how it all works, and how FCGI
might fit in.

Well, it seems to me that each request ought to create a different CGI
object, for the simple reason that each HTTP request has a different set of
parameters - and it's the CGI object that represents them.

I suppose you could 're-use' the previous CGI object, by resetting its
instance variables to the new request, but that's not a very Rubyesque way
of doing things (IMO).

It would be better, I think, to make the object creation faster by not doing
all those slow eval def's each time. For example, if you want to include the
CGI::Html3 module you could first check if it exists, and if it doesn't then
define it (in the slow eval way if that's tidier). Subsequent requests can
just do 'extend CGI::Html3' which is fast. e.g.

unless defined? Html3
module Html3
.. define static methods
end
.. define methods dynamically using eval
end
extend Html3

Regards,

Brian.
 
Ad

Advertisements

P

Patrick May

Hello,

So if I make CGI singleton, then only one instance of it ever exists
--presumably even between http requests. Thus an increase in
performance. But
like I said I'm not perfectly clear about how it all works, and how
FCGI
might fit in.

This is leads to a nice api, ie CGI::params. I think it's more of a
plus for api reasons, than performance. You still end up having some
kind of Connection/Request object per http request.

Cheers,

Patrick
 
T

trans. (T. Onoma)

On Tuesday 02 November 2004 11:29 am, Brian Candler wrote:
| OK, the 'Singleton pattern'. Always seemed rather pointless to me; if
| there's only ever going to be one CGI instance, then you might as well make
| all the methods class methods of CGI itself, and use class instance
| variables.

In fact I asked about that (albeit not in relation to CGI) on the list a
couple weeks ago and three options were brought up: Singleton _pattern_,
Module functions, as you suggest, and an Object with virtual/singleton class.
All are very similar but there does turn out to be a few important
differences.

| Well, it seems to me that each request ought to create a different CGI
| object, for the simple reason that each HTTP request has a different set of
| parameters - and it's the CGI object that represents them.
|
| I suppose you could 're-use' the previous CGI object, by resetting its
| instance variables to the new request, but that's not a very Rubyesque way
| of doing things (IMO).

I see what your saying, but a Singleton can have open parameters that can be
changed in place, too. I have used Singleton CGI myself and it does work. As
for the Ruby Way to do it, you certainly have a point, and probably the most
OOP tack would be to separate out the part that changes from the part that
doesn't. The part that doesn't, i.e. CGI, would then delegate for the part
that does, i.e. the Request. Thus only the changing part need to be
re-instantiated between requests. Seem reasonable? Nonetheless I'm fairly
sure that still won't be as fast as in place changes.

| It would be better, I think, to make the object creation faster by not
| doing all those slow eval def's each time. For example, if you want to
| include the CGI::Html3 module you could first check if it exists, and if it
| doesn't then define it (in the slow eval way if that's tidier). Subsequent
| requests can just do 'extend CGI::Html3' which is fast. e.g.
|
| unless defined? Html3
| module Html3
| .. define static methods
| end
| .. define methods dynamically using eval
| end
| extend Html3

Certainly would help. But again, if you're after speed....

BTW, look what just popped up on RAA:

http://raa.ruby-lang.org/project/apachecgi/

I haven't looked at it yet thought So I'm not sure how it works, but I
suspect...

T.
 
Ad

Advertisements

T

trans. (T. Onoma)

53 PM, trans. (T. Onoma) wrote:
| > Certainly would help. But again, if you're after speed....
| >
| > BTW, look what just popped up on RAA:
| >
| > http://raa.ruby-lang.org/project/apachecgi/
| >
| > I haven't looked at it yet thought So I'm not sure how it works, but I
| > suspect...
| >
| > T.
|
| No. all apachecgi extension does it removes parsing of request
| parameters from the CGI class and delegates it to mod_ruby.

Ah, okay. Thanks, now I don't have to figure it out myself :)

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top