Finding processes using ALSA sound fast
Question
Currently the way /usr/sbin/alsa
in Debian knows the processes using the sound card looks like:
echo $( \
lsof +D /dev -F rt \
| awk '/^p/ {pid=$1} /^t/ {type=$1} /^r0x(74|e)..$/ && type == "tCHR" {print pid}' \
| cut -c 2- \
| uniq \
)
Which is rather ugly and depends on lsof
. I am looking for a POSIX solution without lsof
, perhaps using /proc.
time for i in /proc/*/fd/*; do readlink $i | grep -q /dev/snd/pcm && echo $i | awk -F '/' '{print $3}'; done | uniq
Unfortunately seems to take twice as long as the lsof
based snippet above. Can you make it faster, in order to make it a viable replacement?
Update I rewrote the above as:
#!/bin/sh
for i in /proc/[0-9]*/fd/*
do
if readlink $i | grep -q /dev/snd/pcm
then
IFS=/; set -- $i; unset IFS; echo $3
fi
done
But it seems to have the same performance as my earlier snippet. I suspect grep is the culprit.
Update: I have opened a Debian bug on the topic.
Solution
You start a lot of processes here. Instead you can try doing in a similar way to the lsof script you posted... but replacing lsof by a shell for loop:
If you want to avoid launching lots of grep processes, start only one:
#!/bin/sh
for i in /proc/[0-9]*/fd/*
do
echo ${i%/fd/*} $(readlink $i)
done | grep -q /dev/snd/pcm
This takes now 4.5s on my desktop, compared to 7.5s when there's one grep process for each opened file.
But... your grep is not necessary here, I think. If you care so much, you can try:
#!/bin/sh
for i in /proc/[0-9]*/fd/*
do
var="$(readlink $i)"
if test x"$var" != x"${var#/dev/snd/pcm}"
then
echo $i
fi
done
This is even faster for me (test
is almost always a shell builtin), but I guess this is more because of bad testing methods. Try yourself.
OTHER TIPS
There is an answer for this question on the ALSA FAQ. On my system, using fuser is way faster than using lsof.
fuser -v /dev/snd/*
You don't say what kind of timescales you're looking for but for your alternative suggestion
for i in /proc/[0-9]*/fd/*;
might work and give you a bit of speed up, as might using cut
rather than awk
.