I’m trying to use the “top” command in MacOS X to determine which app is using the resources.
When I do:
top -stats “pid,command”
the command column is truncated, if the process name is too long.
if you look at the activity monitor, the process name is shown properly (with full name) + icon. My questions are:
- how to get the full process name?
- sometimes the app icon show next to the process name, is there anyway to do the similar thing using objective-c? should I simply navigate to the app contents folder and grab the icns image?
First, if you’re trying to get the data programmatically, driving
topis almost definitely not what you want to do.But, to answer your direct questions:
There is no way to control the truncation of commands. You can use the
-ncolsparameter to set the width of the output for non-interactive output, but that doesn’t stoptopfrom truncating if it wants to.No. How would you deal with apps that have multiple .icns files, e.g., for document icons? (Try it with iTunes, for example. If you pick the first .icns, you get the AIFF document icon; if you pick the last, you get the internal-use recent TV shows icon.)
The right way to do it is to get the
NSBundlefor the application, then do something like this:So, how do you actually want to do this, if not by driving
top?Well, what you’re asking for is actually not a well-defined thing. OS X has four different notions of task/process/program/application that don’t correspond 1-to-1, and that makes life difficult if you want to write a mashup of two programs that use different notions—e.g.,
topdeals in BSD processes, while Activity Monitor deals in OS X applications.If what you actually want is the same list
topuses, it’s open source, so you can read it and do the same thing it does.But the simplest way to get the list of BSD processes is probably the interfaces in
libproc.h, in particularproc_listallpidsandproc_pidinfo. For example:Obviously in real code you’re going to want to allocate the buffer dynamically, return the values instead of just dumping them, get more than just the paths, etc. But this is enough to give you the basic idea. (When you go to get additional information, be aware that you if you ask for any struct, you will get an EPERM error unless you have rights to see every member of that struct. So, don’t go asking for
PROC_PIDTASKALLINFOif you only wantPROC_PIDT_SHORTBSDINFO.Anyway, since this API deals with BSD processes (and Mach tasks), not applications, it won’t directly help you get at the
NSBundleyou want to provide Activity Monitor-style features.There is no way to do this that’s entirely correct, but you can probably get away with something like this:
There are probably alternative ways to do this, each with different tradeoffs. For example, using
-[NSWorkspace runningApplications], storing the results in a dictionary mapping the bundle executable path to the bundle, and using that to look up each process is simple, but it only seems to be useful for applications owned by the current user (and probably in the current session). On the other hand, enumerating all bundles on the system, or asking Spotlight, or similar would probably be too slow to do on the fly, but would go out of date if you cached them on first run.Another option, in place of
libproc, is to uselibtop.Unfortunately, Apple doesn’t provide it. They do have a
libtopimplementation, which they use for theirtoptool, but it’s actually embedded in the source totopand not available from outside. You can find the source (at the link above) and embed it into your program the same waytopitself does.Alternatively, both GNU and BSD process utilities have Mac ports (although knowing which name to use with Homebrew/MacPorts/Google search isn’t always easy…), so you could build one of those and use it.
However, unless you’re trying to write cross-platform software (or already know how to write this code for linux or FreeBSD or whatever), I think that just adds extra complexity.