Skip to content

Commit b147004

Browse files
committed
utils/ps: add --children-of-pid
Show a PID and its hierarchy of children. Refs #606 Signed-off-by: Brice Goglin <[email protected]>
1 parent cdf3380 commit b147004

File tree

5 files changed

+96
-7
lines changed

5 files changed

+96
-7
lines changed

contrib/completion/bash/hwloc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright © 2018-2022 Inria. All rights reserved.
2+
# Copyright © 2018-2023 Inria. All rights reserved.
33
# See COPYING in top-level directory.
44
#
55

@@ -480,6 +480,7 @@ complete -F _hwloc_distrib hwloc-distrib
480480
_hwloc_ps(){
481481
local OPTIONS=(-a
482482
--pid
483+
--children-of-pid
483484
--name
484485
--uid
485486
-l --logical
@@ -510,7 +511,7 @@ _hwloc_ps(){
510511
--uid)
511512
COMPREPLY=( "<uid>" "all" "" )
512513
;;
513-
--pid)
514+
--pid|--children-of-pid)
514515
COMPREPLY=( "<pid>" "" )
515516
;;
516517
--pid-cmd)

utils/hwloc/common-ps.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,63 @@ int hwloc_ps_foreach_process(hwloc_topology_t topology, hwloc_const_bitmap_t top
393393
return -1;
394394
#endif /* HAVE_DIRENT_H */
395395
}
396+
397+
int hwloc_ps_foreach_child(hwloc_topology_t topology, hwloc_const_bitmap_t topocpuset,
398+
long pid,
399+
void (*callback)(hwloc_topology_t topology, struct hwloc_ps_process *proc, void *cbdata),
400+
void *cbdata,
401+
unsigned long flags, const char *only_name, long uid)
402+
{
403+
#ifdef HAVE_DIRENT_H
404+
struct hwloc_ps_process proc;
405+
DIR *taskdir;
406+
char path[512];
407+
408+
proc.pid = pid;
409+
proc.cpuset = NULL;
410+
proc.nthreads = 0;
411+
proc.nboundthreads = 0;
412+
proc.threads = NULL;
413+
if (hwloc_ps_read_process(topology, topocpuset, &proc, flags) < 0)
414+
goto next;
415+
if (only_name && !strstr(proc.name, only_name))
416+
goto next;
417+
if (uid != HWLOC_PS_ALL_UIDS && proc.uid != HWLOC_PS_ALL_UIDS && proc.uid != uid)
418+
goto next;
419+
callback(topology, &proc, cbdata);
420+
next:
421+
hwloc_ps_free_process(&proc);
422+
423+
snprintf(path, sizeof(path), "/proc/%ld/task", proc.pid);
424+
taskdir = opendir(path); /* should be enough for the vast majority of cases */
425+
if (taskdir) {
426+
struct dirent *taskdirent;
427+
while ((taskdirent = readdir(taskdir))) {
428+
char pidline[4096];
429+
FILE *file;
430+
char *begin;
431+
size_t len;
432+
snprintf(path, sizeof(path), "/proc/%ld/task/%s/children", proc.pid, taskdirent->d_name);
433+
file = fopen(path, "r");
434+
if (!file)
435+
continue;
436+
len = fread(pidline, 1, sizeof(pidline)-1, file);
437+
fclose(file);
438+
pidline[len] = '\0';
439+
begin = pidline;
440+
while (1) {
441+
char *end;
442+
long childpid = strtoul(begin, &end, 10);
443+
if (end == begin)
444+
break;
445+
hwloc_ps_foreach_child(topology, topocpuset, childpid, callback, cbdata, flags, only_name, uid);
446+
begin = end;
447+
}
448+
}
449+
closedir(taskdir);
450+
}
451+
return 0;
452+
#else /* HAVE_DIRENT_H */
453+
return -1;
454+
#endif /* HAVE_DIRENT_H */
455+
}

utils/hwloc/common-ps.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2009-2021 Inria. All rights reserved.
2+
* Copyright © 2009-2023 Inria. All rights reserved.
33
* Copyright © 2009-2012 Université Bordeaux
44
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
55
* See COPYING in top-level directory.
@@ -45,6 +45,12 @@ int hwloc_ps_foreach_process(hwloc_topology_t topology, hwloc_const_bitmap_t top
4545
void *cbdata,
4646
unsigned long flags, const char *only_name, long only_uid);
4747

48+
int hwloc_ps_foreach_child(hwloc_topology_t topology, hwloc_const_bitmap_t topocpuset,
49+
long pid,
50+
void (*callback)(hwloc_topology_t topology, struct hwloc_ps_process *proc, void *cbdata),
51+
void *cbdata,
52+
unsigned long flags, const char *only_name, long only_uid);
53+
4854
void hwloc_ps_pidcmd(struct hwloc_ps_process *proc, const char *pidcmd);
4955

5056
void hwloc_ps_free_process(struct hwloc_ps_process *proc);

utils/hwloc/hwloc-ps.1in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" -*- nroff -*-
2-
.\" Copyright © 2010-2021 Inria. All rights reserved.
2+
.\" Copyright © 2010-2023 Inria. All rights reserved.
33
.\" Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
44
.\" See COPYING in top-level directory.
55
.TH HWLOC-PS "1" "%HWLOC_DATE%" "%PACKAGE_VERSION%" "%PACKAGE_NAME%"
@@ -28,6 +28,10 @@ specific part of the machine.
2828
Only show process of PID \fI<pid>\fR,
2929
even if it is not bound to any specific part of the machine.
3030
.TP
31+
\fB\-\-children\-of\-pid <pid>\fR
32+
Only show process of PID \fI<pid>\fR and its hierarchy of children,
33+
even if they are not bound to any specific part of the machine.
34+
.TP
3135
\fB\-\-name <name>\fR
3236
Only show processes whose name contains \fI<name>\fR,
3337
even if they are not bound to any specific part of the machine.

utils/hwloc/hwloc-ps.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2009-2022 Inria. All rights reserved.
2+
* Copyright © 2009-2023 Inria. All rights reserved.
33
* Copyright © 2009-2012 Université Bordeaux
44
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
55
* See COPYING in top-level directory.
@@ -35,6 +35,7 @@ static int logical = 1;
3535
static int single_ancestor = 0;
3636
#define NO_ONLY_PID -1
3737
static long only_pid = NO_ONLY_PID;
38+
static long children_of_pid = NO_ONLY_PID;
3839
static long only_uid;
3940
static int json_server = 0;
4041
static int json_port = JSON_PORT;
@@ -47,6 +48,7 @@ void usage(const char *name, FILE *where)
4748
fprintf (where, "Options:\n");
4849
fprintf (where, " -a Show all processes, including those that are not bound\n");
4950
fprintf (where, " --pid <pid> Only show process of pid number <pid>\n");
51+
fprintf (where, " --children-of-pid <pid> Only show process of pid number <pid> and its children\n");
5052
fprintf (where, " --name <name> Only show processes whose name contains <name>\n");
5153
#ifdef HWLOC_LINUX_SYS
5254
fprintf (where, " --uid <uid> Only show processes of the user with the given uid\n");
@@ -197,7 +199,7 @@ static void foreach_process_cb(hwloc_topology_t topology,
197199
const char *pidcmd = cbdata;
198200

199201
/* don't print anything if the process isn't bound and if no threads are bound and if not showing all */
200-
if (!proc->bound && (!proc->nthreads || !proc->nboundthreads) && !show_all && !only_name)
202+
if (!proc->bound && (!proc->nthreads || !proc->nboundthreads) && !show_all && !only_name && children_of_pid == NO_ONLY_PID)
201203
return;
202204

203205
if (pidcmd)
@@ -212,7 +214,11 @@ static void foreach_process_cb(hwloc_topology_t topology,
212214
static int run(hwloc_topology_t topology, hwloc_const_bitmap_t topocpuset,
213215
unsigned long psflags, char *pidcmd)
214216
{
215-
if (only_pid == NO_ONLY_PID) {
217+
if (children_of_pid != NO_ONLY_PID) {
218+
/* show children */
219+
return hwloc_ps_foreach_child(topology, topocpuset, children_of_pid, foreach_process_cb, pidcmd, psflags, only_name, only_uid);
220+
221+
} else if (only_pid == NO_ONLY_PID) {
216222
/* show all */
217223
return hwloc_ps_foreach_process(topology, topocpuset, foreach_process_cb, pidcmd, psflags, only_name, only_uid);
218224

@@ -317,6 +323,7 @@ run_json_server(hwloc_topology_t topology, hwloc_const_bitmap_t topocpuset)
317323

318324
only_name = NULL;
319325
only_pid = NO_ONLY_PID;
326+
children_of_pid = NO_ONLY_PID;
320327
current = req;
321328
while (*current) {
322329
if (!strncmp(current, "lastcpulocation ", 16)) {
@@ -338,6 +345,10 @@ run_json_server(hwloc_topology_t topology, hwloc_const_bitmap_t topocpuset)
338345
psflags |= HWLOC_PS_FLAG_THREADS;
339346
show_all = 1;
340347
break;
348+
} else if (!strncmp(current, "childrenofpid=", 14)) {
349+
children_of_pid = atoi(current+14);
350+
show_all = 1;
351+
break;
341352
} else if (!strncmp(current, "name=", 5)) {
342353
only_name = current+5;
343354
show_all = 1;
@@ -418,6 +429,13 @@ int main(int argc, char *argv[])
418429
}
419430
only_pid = strtol(argv[1], NULL, 10);
420431
opt = 1;
432+
} else if (!strcmp(argv[0], "--children-of-pid")) {
433+
if (argc < 2) {
434+
usage(callname, stderr);
435+
exit(EXIT_FAILURE);
436+
}
437+
children_of_pid = strtol(argv[1], NULL, 10);
438+
opt = 1;
421439
} else if (!strcmp(argv[0], "--name")) {
422440
if (argc < 2) {
423441
usage(callname, stderr);

0 commit comments

Comments
 (0)