diff mbox series

[v12,02/19] multi-process: add configure and usage information

Message ID cc6c74cba091d2735f0dbcba4b5fa28d8a780908.1606853298.git.jag.raman@oracle.com (mailing list archive)
State New, archived
Headers show
Series Initial support for multi-process Qemu | expand

Commit Message

Jag Raman Dec. 1, 2020, 8:22 p.m. UTC
From: Elena Ufimtseva <elena.ufimtseva@oracle.com>

Adds documentation explaining the command-line arguments needed
to use multi-process. Also adds a python script that illustrates the
usage.

Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 docs/multi-process.rst                        | 66 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 tests/multiprocess/multiprocess-lsi53c895a.py | 92 +++++++++++++++++++++++++++
 3 files changed, 159 insertions(+)
 create mode 100644 docs/multi-process.rst
 create mode 100755 tests/multiprocess/multiprocess-lsi53c895a.py

Comments

Marc-André Lureau Dec. 4, 2020, 2:10 p.m. UTC | #1
Hi

On Wed, Dec 2, 2020 at 12:23 AM Jagannathan Raman <jag.raman@oracle.com>
wrote:

> From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
>
> Adds documentation explaining the command-line arguments needed
> to use multi-process. Also adds a python script that illustrates the
> usage.
>
> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
> Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  docs/multi-process.rst                        | 66 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  tests/multiprocess/multiprocess-lsi53c895a.py | 92
> +++++++++++++++++++++++++++
>  3 files changed, 159 insertions(+)
>  create mode 100644 docs/multi-process.rst
>  create mode 100755 tests/multiprocess/multiprocess-lsi53c895a.py
>
> diff --git a/docs/multi-process.rst b/docs/multi-process.rst
> new file mode 100644
> index 0000000..9a5fe5b
> --- /dev/null
> +++ b/docs/multi-process.rst
> @@ -0,0 +1,66 @@
> +Multi-process QEMU
> +==================
> +
> +This document describes how to configure and use multi-process qemu.
> +For the design document refer to docs/devel/qemu-multiprocess.
> +
> +1) Configuration
> +----------------
> +
> +multi-process is enabled by default for targets that enable KVM
> +
> +
> +2) Usage
> +--------
> +
> +Multi-process QEMU requires an orchestrator to launch. Please refer to a
> +light-weight python based orchestrator for mpqemu in
> +scripts/mpqemu-launcher.py to lauch QEMU in multi-process mode.
> +
> +Following is a description of command-line used to launch mpqemu.
> +
> +* Orchestrator:
> +
> +  - The Orchestrator creates a unix socketpair
> +
> +  - It launches the remote process and passes one of the
> +    sockets to it via command-line.
> +
> +  - It then launches QEMU and specifies the other socket as an option
> +    to the Proxy device object
> +
> +* Remote Process:
> +
> +  - QEMU can enter remote process mode by using the "remote" machine
> +    option.
> +
> +  - The orchestrator creates a "remote-object" with details about
> +    the device and the file descriptor for the device
> +
> +  - The remaining options are no different from how one launches QEMU with
> +    devices.
> +
> +  - Example command-line for the remote process is as follows:
> +
> +      /usr/bin/qemu-system-x86_64                                        \
> +      -machine x-remote                                                  \
> +      -device lsi53c895a,id=lsi0                                         \
> +      -drive id=drive_image2,file=/build/ol7-nvme-test-1.qcow2           \
> +      -device scsi-hd,id=drive2,drive=drive_image2,bus=lsi0.0,scsi-id=0  \
> +      -object x-remote-object,id=robj1,devid=lsi1,fd=4,
> +
> +* QEMU:
> +
> +  - Since parts of the RAM are shared between QEMU & remote process, a
> +    memory-backend-memfd is required to facilitate this, as follows:
> +
> +    -object memory-backend-memfd,id=mem,size=2G
> +
> +  - A "x-pci-proxy-dev" device is created for each of the PCI devices
> emulated
> +    in the remote process. A "socket" sub-option specifies the other end
> of
> +    unix channel created by orchestrator. The "id" sub-option must be
> specified
> +    and should be the same as the "id" specified for the remote PCI device
> +
> +  - Example commandline for QEMU is as follows:
> +
> +      -device x-pci-proxy-dev,id=lsi0,socket=3
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 88a5a14..f615ad1 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3136,6 +3136,7 @@ M: Jagannathan Raman <jag.raman@oracle.com>
>  M: John G Johnson <john.g.johnson@oracle.com>
>  S: Maintained
>  F: docs/devel/multi-process.rst
> +F: tests/multiprocess/multiprocess-lsi53c895a.py
>
>  Build and test automation
>  -------------------------
> diff --git a/tests/multiprocess/multiprocess-lsi53c895a.py
> b/tests/multiprocess/multiprocess-lsi53c895a.py
> new file mode 100755
> index 0000000..bfe4f66
> --- /dev/null
> +++ b/tests/multiprocess/multiprocess-lsi53c895a.py
>

This might not be appropriate under qemu tree tests/ imho. It's not a test,
at best it complements the documentation.

@@ -0,0 +1,92 @@
> +#!/usr/bin/env python3
> +
> +import urllib.request
> +import subprocess
> +import argparse
> +import socket
> +import sys
> +import os
> +
> +arch = os.uname()[4]
> +proc_path = os.path.join(os.getcwd(), '..', '..', 'build',
> arch+'-softmmu',
> +                         'qemu-system-'+arch)
> +
> +parser = argparse.ArgumentParser(description='Launcher for multi-process
> QEMU')
> +parser.add_argument('--bin', required=False, help='location of QEMU
> binary',
> +                    metavar='bin');
> +args = parser.parse_args()
> +
> +if args.bin is not None:
> +    proc_path = args.bin
> +
> +if not os.path.isfile(proc_path):
> +    sys.exit('QEMU binary not found')
> +
> +kernel_path = os.path.join(os.getcwd(), 'vmlinuz')
> +initrd_path = os.path.join(os.getcwd(), 'initrd')
> +
> +proxy_cmd = [ proc_path,
>   \
> +              '-name', 'Fedora', '-smp', '4', '-m', '2048', '-cpu',
> 'host', \
> +              '-object', 'memory-backend-memfd,id=sysmem-file,size=2G',
>    \
> +              '-numa', 'node,memdev=sysmem-file',
>    \
> +              '-kernel', kernel_path, '-initrd', initrd_path,
>    \
> +              '-vnc', ':0',
>    \
> +              '-monitor', 'unix:/home/qemu-sock,server,nowait',
>    \
>

That path is odd. Make it a TemporaryFile, or an argument. Even simpler,
use socketpair()

+            ]
> +
> +if arch == 'x86_64':
> +    print('Downloading images for arch x86_64')
> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/x86_64/os/images/'          \
> +                 'pxeboot/vmlinuz'
> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/x86_64/os/images/'          \
> +                 'pxeboot/initrd.img'
> +    proxy_cmd.append('-machine')
> +    proxy_cmd.append('pc,accel=kvm')
> +    proxy_cmd.append('-append')
> +    proxy_cmd.append('rdinit=/bin/bash console=ttyS0 console=tty0')
> +elif arch == 'aarch64':
> +    print('Downloading images for arch aarch64')
> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/aarch64/os/images/'         \
> +                 'pxeboot/vmlinuz'
> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/aarch64/os/images/'         \
> +                 'pxeboot/initrd.img'
> +    proxy_cmd.append('-machine')
> +    proxy_cmd.append('virt,gic-version=3')
> +    proxy_cmd.append('-accel')
> +    proxy_cmd.append('kvm')
> +    proxy_cmd.append('-append')
> +    proxy_cmd.append('rdinit=/bin/bash')
>

We have vm-based testing under tests/vm, can we imagine extending that
instead?

To not delay further the series, I would suggest to drop it for now.

+else:
> +    sys.exit('Arch %s not tested' % arch)
> +
> +urllib.request.urlretrieve(kernel_url, kernel_path)
> +urllib.request.urlretrieve(initrd_url, initrd_path)
> +
> +proxy, remote = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
> +
> +proxy_cmd.append('-device')
> +proxy_cmd.append('x-pci-proxy-dev,id=lsi1,fd='+str(proxy.fileno()))
> +
> +remote_cmd = [ proc_path,
>       \
> +               '-machine', 'x-remote',
>      \
> +               '-device', 'lsi53c895a,id=lsi1',
>       \
> +               '-object',
>       \
> +
>  'x-remote-object,id=robj1,devid=lsi1,fd='+str(remote.fileno()), \
> +               '-display', 'none',
>      \
> +               '-monitor', 'unix:/home/rem-sock,server,nowait',
>       \
> +             ]
> +
> +pid = os.fork();
> +
> +if pid:
> +    # In Proxy
> +    print('Launching QEMU with Proxy object');
> +    process = subprocess.Popen(proxy_cmd, pass_fds=[proxy.fileno()])
> +else:
> +    # In remote
> +    print('Launching Remote process');
> +    process = subprocess.Popen(remote_cmd, pass_fds=[remote.fileno(), 0,
> 1, 2])
> --
> 1.8.3.1
>
>
Daniel P. Berrangé Dec. 4, 2020, 2:37 p.m. UTC | #2
On Tue, Dec 01, 2020 at 03:22:37PM -0500, Jagannathan Raman wrote:
> From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> 
> Adds documentation explaining the command-line arguments needed
> to use multi-process. Also adds a python script that illustrates the
> usage.
> 
> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
> Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  docs/multi-process.rst                        | 66 +++++++++++++++++++
>  MAINTAINERS                                   |  1 +
>  tests/multiprocess/multiprocess-lsi53c895a.py | 92 +++++++++++++++++++++++++++
>  3 files changed, 159 insertions(+)
>  create mode 100644 docs/multi-process.rst
>  create mode 100755 tests/multiprocess/multiprocess-lsi53c895a.py


> diff --git a/tests/multiprocess/multiprocess-lsi53c895a.py b/tests/multiprocess/multiprocess-lsi53c895a.py
> new file mode 100755
> index 0000000..bfe4f66
> --- /dev/null
> +++ b/tests/multiprocess/multiprocess-lsi53c895a.py
> @@ -0,0 +1,92 @@
> +#!/usr/bin/env python3
> +
> +import urllib.request
> +import subprocess
> +import argparse
> +import socket
> +import sys
> +import os
> +
> +arch = os.uname()[4]
> +proc_path = os.path.join(os.getcwd(), '..', '..', 'build', arch+'-softmmu',
> +                         'qemu-system-'+arch)
> +
> +parser = argparse.ArgumentParser(description='Launcher for multi-process QEMU')
> +parser.add_argument('--bin', required=False, help='location of QEMU binary',
> +                    metavar='bin');
> +args = parser.parse_args()
> +
> +if args.bin is not None:
> +    proc_path = args.bin
> +
> +if not os.path.isfile(proc_path):
> +    sys.exit('QEMU binary not found')
> +
> +kernel_path = os.path.join(os.getcwd(), 'vmlinuz')
> +initrd_path = os.path.join(os.getcwd(), 'initrd')
> +
> +proxy_cmd = [ proc_path,                                                    \
> +              '-name', 'Fedora', '-smp', '4', '-m', '2048', '-cpu', 'host', \

I wonder if setting 2 GB of RAM is too large for something that runs by
default as a test.

> +              '-object', 'memory-backend-memfd,id=sysmem-file,size=2G',     \
> +              '-numa', 'node,memdev=sysmem-file',                           \
> +              '-kernel', kernel_path, '-initrd', initrd_path,               \
> +              '-vnc', ':0',                                                 \
> +              '-monitor', 'unix:/home/qemu-sock,server,nowait',             \
> +            ]
> +
> +if arch == 'x86_64':
> +    print('Downloading images for arch x86_64')
> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/x86_64/os/images/'          \
> +                 'pxeboot/vmlinuz'
> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/x86_64/os/images/'          \
> +                 'pxeboot/initrd.img'
> +    proxy_cmd.append('-machine')
> +    proxy_cmd.append('pc,accel=kvm')
> +    proxy_cmd.append('-append')
> +    proxy_cmd.append('rdinit=/bin/bash console=ttyS0 console=tty0')
> +elif arch == 'aarch64':
> +    print('Downloading images for arch aarch64')
> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/aarch64/os/images/'         \
> +                 'pxeboot/vmlinuz'
> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
> +                 'releases/33/Everything/aarch64/os/images/'         \
> +                 'pxeboot/initrd.img'
> +    proxy_cmd.append('-machine')
> +    proxy_cmd.append('virt,gic-version=3')
> +    proxy_cmd.append('-accel')
> +    proxy_cmd.append('kvm')
> +    proxy_cmd.append('-append')
> +    proxy_cmd.append('rdinit=/bin/bash')
> +else:
> +    sys.exit('Arch %s not tested' % arch)

It doens't look like you really need a full OS here. Rather than
downloading the fairly large Fedora images, I'd suggest just using
the kernel that exists on the host OS already in /boot, and then
building a tiny initrd that contains just a static linked busybox.

I have this helper script that could be imported into QEMU for
this purpose:

  https://gitlab.com/berrange/tiny-vm-tools/-/blob/master/make-tiny-image.py

And just skip the test if busybox doesn't exist, or if the vmlinux
in /boot isn't accessible (Debian restricts it to root only IIRC)

> +
> +urllib.request.urlretrieve(kernel_url, kernel_path)
> +urllib.request.urlretrieve(initrd_url, initrd_path)
> +
> +proxy, remote = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
> +
> +proxy_cmd.append('-device')
> +proxy_cmd.append('x-pci-proxy-dev,id=lsi1,fd='+str(proxy.fileno()))
> +
> +remote_cmd = [ proc_path,                                                      \
> +               '-machine', 'x-remote',                                         \
> +               '-device', 'lsi53c895a,id=lsi1',                                \
> +               '-object',                                                      \
> +               'x-remote-object,id=robj1,devid=lsi1,fd='+str(remote.fileno()), \
> +               '-display', 'none',                                             \
> +               '-monitor', 'unix:/home/rem-sock,server,nowait',                \
> +             ]
> +
> +pid = os.fork();
> +
> +if pid:
> +    # In Proxy
> +    print('Launching QEMU with Proxy object');
> +    process = subprocess.Popen(proxy_cmd, pass_fds=[proxy.fileno()])
> +else:
> +    # In remote
> +    print('Launching Remote process');
> +    process = subprocess.Popen(remote_cmd, pass_fds=[remote.fileno(), 0, 1, 2])

Regards,
Daniel
Jag Raman Dec. 9, 2020, 4:20 p.m. UTC | #3
> On Dec 4, 2020, at 9:37 AM, Daniel P. Berrangé <berrange@redhat.com> wrote:
> 
> On Tue, Dec 01, 2020 at 03:22:37PM -0500, Jagannathan Raman wrote:
>> From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
>> 
>> Adds documentation explaining the command-line arguments needed
>> to use multi-process. Also adds a python script that illustrates the
>> usage.
>> 
>> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
>> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
>> Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
>> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
>> ---
>> docs/multi-process.rst                        | 66 +++++++++++++++++++
>> MAINTAINERS                                   |  1 +
>> tests/multiprocess/multiprocess-lsi53c895a.py | 92 +++++++++++++++++++++++++++
>> 3 files changed, 159 insertions(+)
>> create mode 100644 docs/multi-process.rst
>> create mode 100755 tests/multiprocess/multiprocess-lsi53c895a.py
> 
> 
>> diff --git a/tests/multiprocess/multiprocess-lsi53c895a.py b/tests/multiprocess/multiprocess-lsi53c895a.py
>> new file mode 100755
>> index 0000000..bfe4f66
>> --- /dev/null
>> +++ b/tests/multiprocess/multiprocess-lsi53c895a.py
>> @@ -0,0 +1,92 @@
>> +#!/usr/bin/env python3
>> +
>> +import urllib.request
>> +import subprocess
>> +import argparse
>> +import socket
>> +import sys
>> +import os
>> +
>> +arch = os.uname()[4]
>> +proc_path = os.path.join(os.getcwd(), '..', '..', 'build', arch+'-softmmu',
>> +                         'qemu-system-'+arch)
>> +
>> +parser = argparse.ArgumentParser(description='Launcher for multi-process QEMU')
>> +parser.add_argument('--bin', required=False, help='location of QEMU binary',
>> +                    metavar='bin');
>> +args = parser.parse_args()
>> +
>> +if args.bin is not None:
>> +    proc_path = args.bin
>> +
>> +if not os.path.isfile(proc_path):
>> +    sys.exit('QEMU binary not found')
>> +
>> +kernel_path = os.path.join(os.getcwd(), 'vmlinuz')
>> +initrd_path = os.path.join(os.getcwd(), 'initrd')
>> +
>> +proxy_cmd = [ proc_path,                                                    \
>> +              '-name', 'Fedora', '-smp', '4', '-m', '2048', '-cpu', 'host', \
> 
> I wonder if setting 2 GB of RAM is too large for something that runs by
> default as a test.
> 
>> +              '-object', 'memory-backend-memfd,id=sysmem-file,size=2G',     \
>> +              '-numa', 'node,memdev=sysmem-file',                           \
>> +              '-kernel', kernel_path, '-initrd', initrd_path,               \
>> +              '-vnc', ':0',                                                 \
>> +              '-monitor', 'unix:/home/qemu-sock,server,nowait',             \
>> +            ]
>> +
>> +if arch == 'x86_64':
>> +    print('Downloading images for arch x86_64')
>> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
>> +                 'releases/33/Everything/x86_64/os/images/'          \
>> +                 'pxeboot/vmlinuz'
>> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
>> +                 'releases/33/Everything/x86_64/os/images/'          \
>> +                 'pxeboot/initrd.img'
>> +    proxy_cmd.append('-machine')
>> +    proxy_cmd.append('pc,accel=kvm')
>> +    proxy_cmd.append('-append')
>> +    proxy_cmd.append('rdinit=/bin/bash console=ttyS0 console=tty0')
>> +elif arch == 'aarch64':
>> +    print('Downloading images for arch aarch64')
>> +    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
>> +                 'releases/33/Everything/aarch64/os/images/'         \
>> +                 'pxeboot/vmlinuz'
>> +    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
>> +                 'releases/33/Everything/aarch64/os/images/'         \
>> +                 'pxeboot/initrd.img'
>> +    proxy_cmd.append('-machine')
>> +    proxy_cmd.append('virt,gic-version=3')
>> +    proxy_cmd.append('-accel')
>> +    proxy_cmd.append('kvm')
>> +    proxy_cmd.append('-append')
>> +    proxy_cmd.append('rdinit=/bin/bash')
>> +else:
>> +    sys.exit('Arch %s not tested' % arch)
> 
> It doens't look like you really need a full OS here. Rather than
> downloading the fairly large Fedora images, I'd suggest just using
> the kernel that exists on the host OS already in /boot, and then
> building a tiny initrd that contains just a static linked busybox.
> 
> I have this helper script that could be imported into QEMU for
> this purpose:
> 
>  https://gitlab.com/berrange/tiny-vm-tools/-/blob/master/make-tiny-image.py

Hi Daniel,

That’s a nifty script. I was trying to do something similar. Thank you for sharing!

—
Jag

> 
> And just skip the test if busybox doesn't exist, or if the vmlinux
> in /boot isn't accessible (Debian restricts it to root only IIRC)
> 
>> +
>> +urllib.request.urlretrieve(kernel_url, kernel_path)
>> +urllib.request.urlretrieve(initrd_url, initrd_path)
>> +
>> +proxy, remote = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
>> +
>> +proxy_cmd.append('-device')
>> +proxy_cmd.append('x-pci-proxy-dev,id=lsi1,fd='+str(proxy.fileno()))
>> +
>> +remote_cmd = [ proc_path,                                                      \
>> +               '-machine', 'x-remote',                                         \
>> +               '-device', 'lsi53c895a,id=lsi1',                                \
>> +               '-object',                                                      \
>> +               'x-remote-object,id=robj1,devid=lsi1,fd='+str(remote.fileno()), \
>> +               '-display', 'none',                                             \
>> +               '-monitor', 'unix:/home/rem-sock,server,nowait',                \
>> +             ]
>> +
>> +pid = os.fork();
>> +
>> +if pid:
>> +    # In Proxy
>> +    print('Launching QEMU with Proxy object');
>> +    process = subprocess.Popen(proxy_cmd, pass_fds=[proxy.fileno()])
>> +else:
>> +    # In remote
>> +    print('Launching Remote process');
>> +    process = subprocess.Popen(remote_cmd, pass_fds=[remote.fileno(), 0, 1, 2])
> 
> Regards,
> Daniel
> -- 
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
> 
>
diff mbox series

Patch

diff --git a/docs/multi-process.rst b/docs/multi-process.rst
new file mode 100644
index 0000000..9a5fe5b
--- /dev/null
+++ b/docs/multi-process.rst
@@ -0,0 +1,66 @@ 
+Multi-process QEMU
+==================
+
+This document describes how to configure and use multi-process qemu.
+For the design document refer to docs/devel/qemu-multiprocess.
+
+1) Configuration
+----------------
+
+multi-process is enabled by default for targets that enable KVM
+
+
+2) Usage
+--------
+
+Multi-process QEMU requires an orchestrator to launch. Please refer to a
+light-weight python based orchestrator for mpqemu in
+scripts/mpqemu-launcher.py to lauch QEMU in multi-process mode.
+
+Following is a description of command-line used to launch mpqemu.
+
+* Orchestrator:
+
+  - The Orchestrator creates a unix socketpair
+
+  - It launches the remote process and passes one of the
+    sockets to it via command-line.
+
+  - It then launches QEMU and specifies the other socket as an option
+    to the Proxy device object
+
+* Remote Process:
+
+  - QEMU can enter remote process mode by using the "remote" machine
+    option.
+
+  - The orchestrator creates a "remote-object" with details about
+    the device and the file descriptor for the device
+
+  - The remaining options are no different from how one launches QEMU with
+    devices.
+
+  - Example command-line for the remote process is as follows:
+
+      /usr/bin/qemu-system-x86_64                                        \
+      -machine x-remote                                                  \
+      -device lsi53c895a,id=lsi0                                         \
+      -drive id=drive_image2,file=/build/ol7-nvme-test-1.qcow2           \
+      -device scsi-hd,id=drive2,drive=drive_image2,bus=lsi0.0,scsi-id=0  \
+      -object x-remote-object,id=robj1,devid=lsi1,fd=4,
+
+* QEMU:
+
+  - Since parts of the RAM are shared between QEMU & remote process, a
+    memory-backend-memfd is required to facilitate this, as follows:
+
+    -object memory-backend-memfd,id=mem,size=2G
+
+  - A "x-pci-proxy-dev" device is created for each of the PCI devices emulated
+    in the remote process. A "socket" sub-option specifies the other end of
+    unix channel created by orchestrator. The "id" sub-option must be specified
+    and should be the same as the "id" specified for the remote PCI device
+
+  - Example commandline for QEMU is as follows:
+
+      -device x-pci-proxy-dev,id=lsi0,socket=3
diff --git a/MAINTAINERS b/MAINTAINERS
index 88a5a14..f615ad1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3136,6 +3136,7 @@  M: Jagannathan Raman <jag.raman@oracle.com>
 M: John G Johnson <john.g.johnson@oracle.com>
 S: Maintained
 F: docs/devel/multi-process.rst
+F: tests/multiprocess/multiprocess-lsi53c895a.py
 
 Build and test automation
 -------------------------
diff --git a/tests/multiprocess/multiprocess-lsi53c895a.py b/tests/multiprocess/multiprocess-lsi53c895a.py
new file mode 100755
index 0000000..bfe4f66
--- /dev/null
+++ b/tests/multiprocess/multiprocess-lsi53c895a.py
@@ -0,0 +1,92 @@ 
+#!/usr/bin/env python3
+
+import urllib.request
+import subprocess
+import argparse
+import socket
+import sys
+import os
+
+arch = os.uname()[4]
+proc_path = os.path.join(os.getcwd(), '..', '..', 'build', arch+'-softmmu',
+                         'qemu-system-'+arch)
+
+parser = argparse.ArgumentParser(description='Launcher for multi-process QEMU')
+parser.add_argument('--bin', required=False, help='location of QEMU binary',
+                    metavar='bin');
+args = parser.parse_args()
+
+if args.bin is not None:
+    proc_path = args.bin
+
+if not os.path.isfile(proc_path):
+    sys.exit('QEMU binary not found')
+
+kernel_path = os.path.join(os.getcwd(), 'vmlinuz')
+initrd_path = os.path.join(os.getcwd(), 'initrd')
+
+proxy_cmd = [ proc_path,                                                    \
+              '-name', 'Fedora', '-smp', '4', '-m', '2048', '-cpu', 'host', \
+              '-object', 'memory-backend-memfd,id=sysmem-file,size=2G',     \
+              '-numa', 'node,memdev=sysmem-file',                           \
+              '-kernel', kernel_path, '-initrd', initrd_path,               \
+              '-vnc', ':0',                                                 \
+              '-monitor', 'unix:/home/qemu-sock,server,nowait',             \
+            ]
+
+if arch == 'x86_64':
+    print('Downloading images for arch x86_64')
+    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
+                 'releases/33/Everything/x86_64/os/images/'          \
+                 'pxeboot/vmlinuz'
+    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
+                 'releases/33/Everything/x86_64/os/images/'          \
+                 'pxeboot/initrd.img'
+    proxy_cmd.append('-machine')
+    proxy_cmd.append('pc,accel=kvm')
+    proxy_cmd.append('-append')
+    proxy_cmd.append('rdinit=/bin/bash console=ttyS0 console=tty0')
+elif arch == 'aarch64':
+    print('Downloading images for arch aarch64')
+    kernel_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
+                 'releases/33/Everything/aarch64/os/images/'         \
+                 'pxeboot/vmlinuz'
+    initrd_url = 'https://dl.fedoraproject.org/pub/fedora/linux/'    \
+                 'releases/33/Everything/aarch64/os/images/'         \
+                 'pxeboot/initrd.img'
+    proxy_cmd.append('-machine')
+    proxy_cmd.append('virt,gic-version=3')
+    proxy_cmd.append('-accel')
+    proxy_cmd.append('kvm')
+    proxy_cmd.append('-append')
+    proxy_cmd.append('rdinit=/bin/bash')
+else:
+    sys.exit('Arch %s not tested' % arch)
+
+urllib.request.urlretrieve(kernel_url, kernel_path)
+urllib.request.urlretrieve(initrd_url, initrd_path)
+
+proxy, remote = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+
+proxy_cmd.append('-device')
+proxy_cmd.append('x-pci-proxy-dev,id=lsi1,fd='+str(proxy.fileno()))
+
+remote_cmd = [ proc_path,                                                      \
+               '-machine', 'x-remote',                                         \
+               '-device', 'lsi53c895a,id=lsi1',                                \
+               '-object',                                                      \
+               'x-remote-object,id=robj1,devid=lsi1,fd='+str(remote.fileno()), \
+               '-display', 'none',                                             \
+               '-monitor', 'unix:/home/rem-sock,server,nowait',                \
+             ]
+
+pid = os.fork();
+
+if pid:
+    # In Proxy
+    print('Launching QEMU with Proxy object');
+    process = subprocess.Popen(proxy_cmd, pass_fds=[proxy.fileno()])
+else:
+    # In remote
+    print('Launching Remote process');
+    process = subprocess.Popen(remote_cmd, pass_fds=[remote.fileno(), 0, 1, 2])