Skip to content

Commit

Permalink
Merge branch 'main' into einsum_wip
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleHerndon authored Sep 25, 2024
2 parents 478e415 + 61eacac commit f2c4fc0
Show file tree
Hide file tree
Showing 73 changed files with 3,272 additions and 448 deletions.
1 change: 1 addition & 0 deletions libshortfin/build_tools/python_lsan_suppressions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ leak:numpy
leak:_mlir_libs
leak:google/_upb
leak:import_find_and_load
leak:pyo3::pyclass::create_type_object
leak:ufunc
20 changes: 20 additions & 0 deletions libshortfin/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Python API Docs

Documentation for the Python API is build with Sphinx under this directory.

## Building docs

The Python modules will be automatically imported if installed or if the build
is located at `../build`, relative to this file.

### Install dependencies

```shell
python3 -m pip install -r requirements.txt
```

### Build the docs

```shell
sphinx-build -b html . _build
```
42 changes: 42 additions & 0 deletions libshortfin/docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2024 Advanced Micro Devices, Inc.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import os
import sys

try:
import _shortfin_default
except ImportError:
sys.path.insert(0, os.path.abspath("../build/python/"))
import _shortfin_default

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "libshortfin"
copyright = "2024, Advanced Micro Devices, Inc"
author = "libshortfin Authors"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
"sphinx.ext.autodoc",
]

templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "sphinx_rtd_theme"
html_static_path = ["_static"]
27 changes: 27 additions & 0 deletions libshortfin/docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.. Copyright 2024 Advanced Micro Devices, Inc.
.. libshortfin documentation master file, created by
sphinx-quickstart on Fri Sep 6 16:31:45 2024.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to libshortfin's documentation!
=======================================

.. toctree::
:maxdepth: 2
:caption: Contents

.. toctree::
:maxdepth: 2
:caption: Reference

reference


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
58 changes: 58 additions & 0 deletions libshortfin/docs/reference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. Copyright 2024 Advanced Micro Devices, Inc.
.. py:module:: _shortfin_default.lib
.. _reference:

API Reference
=============

Array
--------------
.. automodule:: _shortfin_default.lib.array
.. autoclass:: DType
.. autoclass:: storage
:members:
.. autoclass:: base_array
.. autoclass:: device_array

Local
--------------

.. automodule:: _shortfin_default.lib.local

.. autoclass:: SystemBuilder
.. autoclass:: System
.. autoclass:: Node
.. autoclass:: Device
.. autoclass:: DeviceAffinity
.. autoclass:: Program
.. autoclass:: ProgramFunction
:members:
.. autoclass:: ProgramModule
.. autoclass:: ProgramInvocation
.. autoclass:: Fiber
.. autoclass:: ScopedDevice
.. autoclass:: Worker
.. autoclass:: Process
.. autoclass:: CompletionEvent
.. autoclass:: Message
.. autoclass:: Queue
.. autoclass:: QueueWriter
.. autoclass:: QueueReader
.. autoclass:: Future
.. autoclass:: VoidFuture
.. autoclass:: MessageFuture


AMD GPU
^^^^^^^
.. automodule:: _shortfin_default.lib.local.amdgpu
.. autoclass:: SystemBuilder
.. autoclass:: AMDGPUDevice

Host
^^^^^^^
.. automodule:: _shortfin_default.lib.local.host
.. autoclass:: CPUSystemBuilder
.. autoclass:: HostCPUDevice
2 changes: 2 additions & 0 deletions libshortfin/docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sphinx==7.4.7
sphinx_rtd_theme==2.0.0
8 changes: 4 additions & 4 deletions libshortfin/examples/python/async/device_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class MyProcess(sf.Process):
async def run(self):
device = self.scope.device(0)
device = self.fiber.device(0)
ary1 = snp.device_array(device, [32, 1, 4], snp.int32)
ary1.storage.fill(array.array("i", [0]))
print(f"[pid:{self.pid}] ARY1:", ary1)
Expand All @@ -27,11 +27,11 @@ async def run(self):

async def main():
worker = lsys.create_worker("main")
scope = lsys.create_scope(worker)
fiber = lsys.create_fiber(worker)
print("+++ Launching process")
await asyncio.gather(
MyProcess(scope=scope).launch(),
MyProcess(scope=scope).launch(),
MyProcess(fiber=fiber).launch(),
MyProcess(fiber=fiber).launch(),
)
print("--- Process terminated")

Expand Down
10 changes: 5 additions & 5 deletions libshortfin/examples/python/async/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def run(self):
processes = []
if self.arg < 10:
await asyncio.sleep(0.1)
processes.append(MyProcess(self.arg + 1, scope=self.scope).launch())
processes.append(MyProcess(self.arg + 1, fiber=self.fiber).launch())
await asyncio.gather(*processes)
print(f"[pid:{self.pid}] Goodbye async:", self.arg, self)
tick_total()
Expand All @@ -41,14 +41,14 @@ async def run(self):
async def main():
def create_worker(i):
worker = lsys.create_worker(f"main-{i}")
return lsys.create_scope(worker)
return lsys.create_fiber(worker)

workers = [create_worker(i) for i in range(3)]
processes = []
for i in range(10):
processes.append(MyProcess(i, scope=workers[i % len(workers)]).launch())
processes.append(MyProcess(i * 100, scope=workers[i % len(workers)]).launch())
processes.append(MyProcess(i * 1000, scope=workers[i % len(workers)]).launch())
processes.append(MyProcess(i, fiber=workers[i % len(workers)]).launch())
processes.append(MyProcess(i * 100, fiber=workers[i % len(workers)]).launch())
processes.append(MyProcess(i * 1000, fiber=workers[i % len(workers)]).launch())
await asyncio.sleep(0.1)

print("<<MAIN WAITING>>")
Expand Down
10 changes: 5 additions & 5 deletions libshortfin/examples/python/async/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ async def run(self):

async def main():
queue = lsys.create_queue()
main_scope = lsys.create_scope()
main_fiber = lsys.create_fiber()
# TODO: Also test named queues.
# queue = lsys.create_queue("infeed")
w1 = lsys.create_worker("w1")
w1_scope = lsys.create_scope(w1)
w1_fiber = lsys.create_fiber(w1)
await asyncio.gather(
WriterProcess(queue, scope=main_scope).launch(),
WriterProcess(queue, fiber=main_fiber).launch(),
# By having a reader on the main worker and a separate worker,
# we test both intra and inter worker future resolution, which
# take different paths internally.
ReaderProcess(queue, scope=main_scope).launch(),
ReaderProcess(queue, scope=w1_scope).launch(),
ReaderProcess(queue, fiber=main_fiber).launch(),
ReaderProcess(queue, fiber=w1_fiber).launch(),
)


Expand Down
24 changes: 12 additions & 12 deletions libshortfin/examples/python/mobilenet_server/inference_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, program, request_queue, **kwargs):
super().__init__(**kwargs)
self.main_function = program["module.torch-jit-export"]
self.request_reader = request_queue.reader()
self.device = self.scope.device(0)
self.device = self.fiber.device(0)
self.device_input = sfnp.device_array(
self.device, [MAX_BATCH, 3, 224, 224], sfnp.float32
)
Expand Down Expand Up @@ -57,20 +57,20 @@ async def run(self):
print("Result 2:", result2)

# Explicit invocation object.
# inv = self.main_function.invocation(scope=self.scope)
# inv = self.main_function.invocation(fiber=self.fiber)
# inv.add_arg(self.device_input)
# results = await inv.invoke()
# print("results:", results)

# Multiple invocations in parallel.
# all_results = await asyncio.gather(
# self.main_function(self.device_input, scope=self.scope),
# self.main_function(self.device_input, scope=self.scope),
# self.main_function(self.device_input, scope=self.scope),
# self.main_function(self.device_input, fiber=self.fiber),
# self.main_function(self.device_input, fiber=self.fiber),
# self.main_function(self.device_input, fiber=self.fiber),
# )
# print("All results:", all_results)

# output = await self.scope.invoke(self.main_function, self.device_input)
# output = await self.fiber.invoke(self.main_function, self.device_input)
# print("OUTPUT:", output)
# read_back = self.device_input.for_transfer()
# read_back.copy_from(self.device_input)
Expand All @@ -88,14 +88,14 @@ def __init__(self, lsys: sf.System, home_dir: Path):
print(f"Loaded: {self.program_module}")
self.processes = []

async def start_scope(self, scope):
async def start_fiber(self, fiber):
# Note that currently, program load is synchronous. But we do it
# in a task so we can await it in the future and let program loads
# overlap.
for _ in range(self.processes_per_worker):
program = sf.Program([self.program_module], scope=scope)
program = sf.Program([self.program_module], fiber=fiber)
self.processes.append(
InferenceProcess(program, self.request_queue, scope=scope).launch()
InferenceProcess(program, self.request_queue, fiber=fiber).launch()
)

async def main(self):
Expand All @@ -104,14 +104,14 @@ async def main(self):
f"System created with {len(devices)} devices:\n "
f"{' '.join(repr(d) for d in devices)}"
)
# We create a physical worker and initial scope for each device.
# We create a physical worker and initial fiber for each device.
# This isn't a hard requirement and there are advantages to other
# topologies.
initializers = []
for device in devices:
worker = self.lsys.create_worker(f"device-{device.name}")
scope = self.lsys.create_scope(worker, devices=[device])
initializers.append(self.start_scope(scope))
fiber = self.lsys.create_fiber(worker, devices=[device])
initializers.append(self.start_fiber(fiber))

# Run all initializers in parallel. These launch inference processes.
print("Waiting for initializers")
Expand Down
1 change: 1 addition & 0 deletions libshortfin/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ FetchContent_MakeAvailable(nanobind)

nanobind_add_module(shortfin_python_extension NB_STATIC LTO
array_binding.cc
array_host_ops.cc
lib_ext.cc
)

Expand Down
Loading

0 comments on commit f2c4fc0

Please sign in to comment.