Someone was asking on a list why their program wasn't getting expected results (had to due with "unit of measurement" inconsistencies). But to test they'd written the program in python -- for 9 threads, they got < 2 cores utilization. I was curious how perl would do. So I tried to follow the python structure as much as possible.
First the programs, python:
#!/usr/bin/python
import operator
import hashlib
from threading import Thread
def ticks_all():
with open('/proc/stat') as f:
cpu = f.readline().split()
return (int(cpu[1]), int(cpu[3]))
def ticks_process():
with open('/proc/self/stat') as f:
cpu = f.readline().split()
return (int(cpu[13]), int(cpu[14]))
def do_work():
d = hashlib.md5()
d.update('nobody inspects')
for i in xrange(0, 10000000):
d.update(' the spammish repetition')
before_all_user, before_all_sys = ticks_all()
before_process_user, before_process_sys = ticks_process()
threads = []
for i in xrange(0, 8):
t = Thread(target=do_work)
threads.append(t)
t.start()
for t in threads:
t.join()
after_process_user, after_process_sys = ticks_process()
after_all_user, after_all_sys = ticks_all()
print 'delta process: user:', after_process_user - before_process_user
+, 'sys:', after_process_sys - before_process_sys
print 'delta all: user:', after_all_user - before_all_user, 'sys:', af
+ter_all_sys - before_all_sys
Then my attempt at a perl approximation (I don't really know python, so if anyone sees anywhere I booboo'd, feel free to
politely point it out ;-).
#!/usr/bin/perl
use 5.16.0;
use threads;
sub open_for_read($) {
open(my $handle, "<$_[0]") or die "opening $_[0]: $!";
$handle }
sub ticks_all {
my $f = open_for_read("/proc/stat");
return (split ' ', <$f>)[1,3] }
sub ticks_process() {
my $f = open_for_read("/proc/self/stat");
return (split ' ', <$f>)[13,14] }
sub dowork () {
use Digest::MD5;
my $d = Digest::MD5->new;
$d->add('nobody inspects');
$d->add(' the spammish repetition') for (0 .. 10_000_000)}
my ($before_all_user, $before_all_sys) = ticks_all();
my ($before_process_user, $before_process_sys) = ticks_process();
my @threads;
for my $i (0 .. 8) {
my $t = threads->create(\&dowork);
push @threads,$t }
$_->join() foreach @threads;
my ($after_all_user, $after_all_sys) = ticks_all();
my ($after_process_user, $after_process_sys) = ticks_process();
#(note: changing perl defaults for print)
$, = " "; #put spaces between output fields
$\ = "\n"; #add LF to end of lines by default
print 'delta process: user:', $after_process_user - $before_process_us
+er,
' sys:', $after_process_sys - $before_process_sys;
print 'delta all: user:', $after_all_user - $before_all_user,
' sys: ', $after_all_sys - $before_all_sys;
The results:
> export TIMEFORMAT="%2Rsec %2Uusr %2Ssys (%P%% cpu)"
> time python ticks.py
delta process: user: 9263 sys: 2987
delta all: user: 6034 sys: 2178
67.35sec 92.64usr 29.89sys (181.94% cpu)
> time perl /tmp/pticks
delta process: user: 2917 sys: 3
delta all: user: 2926 sys: 25
3.36sec 29.20usr 0.03sys (870.05% cpu)
---
For 9 threads:
lang #thrds #coresuse %efficency
python 9 1.82 20.2%
perl 9 8.70 96.7%
I tried to use as close to same semantics
as the python program. Even used python indentation where
practical (I did split the prints at the end... something
python seems to have problems with...)