This is a continuation of the first post, Hacker School Day 40 – Making pstree Faster/Ugly.
The last part in the race to make my pstree clone super fast was to replace the call to filepath.Glob. Globbing is a way to grab up files that match a certain pattern. It’s seen often in the shell:
Globbing is useful when dealing with /proc, since every file under this tree that looks like a number, is a directory with information about a process. Many programs do their process parsing by looping over /proc/[0-9]*
I was doing this as well, and the profiler was pointing me here for my next target. At this point, pstree was already ridiculously fast, but the point of the exercise was to see how far I could take it. So I replaced it.
You can use readdir to get the contents of a directory. /proc contains files other than the PID directories, so you have to filter out the non-digit names. One way of doing this might be a regex:
if (the_file doesn’t look like [0-9]*) skip
But that would defeat the point of my prior post, so I couldn’t use that. Another method might be to try converting the string to a number, then checking for an error. You can do this with strconv.Atoi. But I don’t care about the actual number, I just care if it looks like a number! Atoi also has a lot of extra logic I don’t need — it’ll try to see if you’re converting a hex number, it’ll try to determine what size int it is, and it’ll check for negative signs among other things. The input range is well-defined for me, and I don’t need any of that.
So I wrote a small helper method called isInt, which is mostly ripped from the bowels of strconv’s ParseUint function. It compares each byte in the string to check if it’s between the ‘0’ and ‘9’ character and returns false if any character isn’t. That’s all I needed, and it worked out great 🙂
Those are all the changes I made to drop the speed of the main method of the program from 5.9 milliseconds to 1.5 ms, a near 4x increase in speed. I’m sure there are some other changes I could make that I don’t see or understand yet, but I have a couple other things to follow up on first:
- Why did the weird /proc thing happen? Is it intentional or is there a missing if-check that could be added to procfs?
- Should I contribute a fix to the documentation for File.Read or was I being dense?
- The tangent I haven’t written yet: the long, long way of reading a process’s command line invocation.
Thanks for following along! Let me know if you can think of any other speedups!