1515 You should have received a copy of the GNU General Public License
1616 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1717
18+ /* Shared driver program for the gdb.rocm multi-inferior tests.
19+
20+ The parent process forks N children; each child re-execs itself so
21+ that its GPU runtime is initialized in a clean address space, then
22+ launches its own GPU kernel. Re-exec'ing makes each child a separate
23+ process from the operating system's point of view, which is what the
24+ multi-inferior tests debug concurrently.
25+
26+ N comes from argv[1] when given; otherwise it defaults to the number
27+ of GPU devices found at runtime (one child per device). The
28+ companion .exp helpers in lib/rocm.exp plant breakpoints on the
29+ pre-fork and post-join source markers and on the kernel. */
30+
1831#include < sys/types.h>
1932#include < sys/wait.h>
2033#include < unistd.h>
2134#include < hip/hip_runtime.h>
35+ #include < errno.h>
2236#include < stdio.h>
2337#include < stdlib.h>
38+ #include < string.h>
39+ #include < string>
2440
2541#include " rocm-test-utils.h"
2642
@@ -30,77 +46,99 @@ kern ()
3046 asm (" s_sleep 1" );
3147}
3248
33- /* Spawn one child process per detected GPU. */
49+ static int
50+ child (int argc, char **argv)
51+ {
52+ if (argc < 4 )
53+ {
54+ fprintf (stderr, " %s: expected: child <idx> <num_devices>\n " ,
55+ argv[0 ]);
56+ return -1 ;
57+ }
58+
59+ int idx = atoi (argv[2 ]);
60+ int num_devices = atoi (argv[3 ]);
61+ if (num_devices <= 0 )
62+ {
63+ fprintf (stderr, " child %d: invalid num_devices %d\n " , idx,
64+ num_devices);
65+ return -1 ;
66+ }
67+
68+ CHECK (hipSetDevice (idx % num_devices));
69+ kern<<<1 , 1 >>> ();
70+ CHECK (hipDeviceSynchronize ());
71+ return 0 ;
72+ }
73+
74+ /* Spawn NUM_CHILDREN child processes. When NUM_CHILDREN is not
75+ positive, spawn one child per detected GPU device. */
3476
3577static int
36- parent (int argc, char **argv )
78+ parent (const char *argv0, int num_children )
3779{
38- /* Identify how many GPUs we have, and spawn one child for each. */
3980 int num_devices;
4081 CHECK (hipGetDeviceCount (&num_devices));
82+ if (num_devices <= 0 )
83+ {
84+ fprintf (stderr, " no GPU devices available\n " );
85+ return -1 ;
86+ }
87+
88+ if (num_children <= 0 )
89+ num_children = num_devices;
4190
4291 /* Break here. */
4392
44- for (int i = 0 ; i < num_devices ; i++)
93+ for (int i = 0 ; i < num_children ; i++)
4594 {
46- char n[32 ] = {};
47- snprintf (n, sizeof (n), " %d" , i);
95+ std::string idx_str = std::to_string (i);
96+ std::string ndev_str = std::to_string (num_devices);
97+
4898 pid_t pid = fork ();
4999 if (pid == -1 )
50100 {
51- perror (" Fork failed " );
101+ perror (" fork " );
52102 return -1 ;
53103 }
54104
55105 if (pid == 0 )
56106 {
57- /* Exec to force the child to re-initialize the ROCm runtime. */
58- if ( execl (argv[ 0 ], argv[ 0 ], n, nullptr ) == -1 )
107+ if ( execl (argv0, argv0, " child" , idx_str. c_str (),
108+ ndev_str. c_str (), ( char *) nullptr ) == -1 )
59109 {
60- perror (" Failed to exec " );
61- return - 1 ;
110+ perror (" execl " );
111+ _exit ( 127 ) ;
62112 }
63113 }
64114 }
65115
66- /* Wait for all children. */
116+ /* Reap every child. Any non-zero exit from a child is a failure
117+ (e.g. a runtime initialization failure under contention). */
118+ int failed = 0 ;
67119 while (true )
68120 {
69121 int ws;
70122 pid_t ret = waitpid (-1 , &ws, 0 );
71123 if (ret == -1 && errno == ECHILD )
72124 break ;
125+ if (ret > 0 && (!WIFEXITED (ws) || WEXITSTATUS (ws) != 0 ))
126+ failed++;
73127 }
74128
75129 /* Last break here. */
76- return 0 ;
77- }
78-
79- static int
80- child (int argc, char **argv)
81- {
82- int dev_number;
83- if (sscanf (argv[1 ], " %d" , &dev_number) != 1 )
84- {
85- fprintf (stderr, " Invalid argument \" %s\"\n " , argv[1 ]);
86- return -1 ;
87- }
88-
89- CHECK (hipSetDevice (dev_number));
90- kern<<<1 , 1 >>> ();
91- CHECK (hipDeviceSynchronize ());
92- return 0 ;
130+ return failed == 0 ? 0 : 1 ;
93131}
94132
95- /* When called with no argument, identify how many AMDGPU devices are
96- available on the system and spawn one worker process per GPU. If a
97- command-line argument is provided, it is the index of the GPU to use. */
98-
99133int
100134main (int argc, char **argv)
101135{
102- if (argc <= 1 )
103- return parent (argc, argv);
104- else
136+ if (argc >= 2 && strcmp (argv[1 ], " child" ) == 0 )
105137 return child (argc, argv);
138+
139+ int num_children = 0 ;
140+ if (argc >= 2 )
141+ num_children = atoi (argv[1 ]);
142+
143+ return parent (argv[0 ], num_children);
106144}
0 commit comments