Java Library

The UPMEM DPU toolchain contains a Java Host library to manage DPUs. It is based on the C Host library and provides a subset of its features, which should cover the main use cases. Knowing the C API should not be necessary to understand the Java API.

Contents

The detailed documentation of the API can be found in the Reference to the Java API.

JDK prerequisite

This API relies on a JDK 8 or higher.

Jar location

The DPU Java host API jar file can be found by running the command dpu-pkg-config --variable=java dpu. This is notably useful to add the jar to the classpath of the application.

Maven installation

To add the jar in Maven local repository, simply run:

mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -Dfile="$(dpu-pkg-config --variable=java dpu)"

You can then add the API as a dependency in the pom.xml file.

Overview

The following code is an example of a Java application with a simple DPU program with no real use case. The goal here is to present some of the main features of the Java API.

import com.upmem.dpu.Dpu;
import com.upmem.dpu.DpuException;
import com.upmem.dpu.DpuSystem;

public class JavaExample {
    public static void main(String[] args) throws DpuException {
        try(DpuSystem system = DpuSystem.allocate(1, "")) {
            Dpu dpu = system.dpus().get(0);

            byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6, 7};
            byte[] result = new byte[8];

            dpu.load("java_example.dpu");
            dpu.copy("variable", data);
            dpu.exec(System.out);
            dpu.copy(result, "variable");

            long value =
                ((result[0] & 0xffl) << (8 * 0)) |
                ((result[1] & 0xffl) << (8 * 1)) |
                ((result[2] & 0xffl) << (8 * 2)) |
                ((result[3] & 0xffl) << (8 * 3)) |
                ((result[4] & 0xffl) << (8 * 4)) |
                ((result[5] & 0xffl) << (8 * 5)) |
                ((result[6] & 0xffl) << (8 * 6)) |
                ((result[7] & 0xffl) << (8 * 7));

            System.out.println(String.format("Variable after = 0x%016x", value));
        }
    }
}

Here is the DPU program, written in C:

#include <mram.h>
#include <stdint.h>
#include <stdio.h>

__mram uint64_t variable; // Initialized by the host application

int main() {
    uint64_t data = variable;
    printf("Variable before = 0x%016lx\n", data);

    variable = data + 1;

    return 0;
}

Calling the static method DpuSystem.allocate will allocate a number of DPUs. In the example, we are allocating a single DPU with the default profile. It can be used in a try-with-resources statement: the allocated DPUs will be freed at the end of the block.

The DPU program is loaded with the DpuSet.load method. It is then executed with the DpuSet.exec method. Here System.out is provided as a log stream, to print the DPU logs on the host standard output.

The DpuSet.copy methods can be used to read and write the DPU memory, using the symbols defined with the attributes __mram or __host in the DPU program. Here we are using the Dpu.copy method which provides a simpler prototype.

For a real application, the load, copy and exec methods would be used on the whole system, or at least on each rank of the system (the rank list can be fetched with the DpuSet.ranks method).

The program can be run with:

java -cp .:$(dpu-pkg-config --variable=java dpu) JavaExample

And will give the output:

=== DPU#0x0 ===
Variable before = 0x0706050403020100
Variable after = 0x0706050403020101

Debugging

Some rudimentary debugging features are available when using the Java API. It is possible to use dpu-lldb to observe and attach to running DPUs. Notably, as described in Debugging a Host application, the dpu_attach_on_boot command will be useful to debug a DPU program.

Currently, the same features are not available while using jdb.