#Which MPI wrapper version is better?

1 messages · Page 1 of 1 (latest)

fleet helm
#

I am making a wrapper for MPI and been trying to make it "zig-like". However, due to some details of MPI this is proving to be difficult, especially since I want to maintain a clean API. Anyways, I need help deciding which of the following is better. This first snippet shows a very thin API, where the functions keep the same signature as the c ones:

pub fn main() !void {
    try mpi.init();

    const comm: mpi.Comm = .world;
    const rank = try comm.rank();

    if (rank == 0) {
        const val: f64 = 3.14;

        try comm.send(
            &val,
            1,
            mpi.datatype.double,
            1,
            0,
        );
    } else if (rank == 1) {
        var val: f64 = undefined;

        _ = try comm.recv(
            &val,
            1,
            mpi.datatype.double,
            0,
            0,
        );

        std.debug.print("Process {d} received from process 0 value: {d}\n", .{ rank, val });
    }

    try mpi.finalize();
}

The second snippet is my attempt at a more zig-like version:

pub fn main() !void {
    const a: std.mem.Allocator = std.heap.page_allocator;

    try mpi.init(a);

    const comm: mpi.Comm = .world;
    const rank = try comm.rank();

    if (rank == 0) {
        const val: f64 = 3.14;

        try comm.send(
            f64,
            .{
                .slice = &.{val},
                .kind = .none,
            },
            1,
            0,
        );
    } else if (rank == 1) {
        var val: [1]f64 = .{0.0};
        _ = try comm.recv(
            f64,
            .{
                .slice = &val,
                .kind = .none,
            },
            0,
            0,
        );

        std.debug.print("Process {d} received from process 0 value: {d}\n", .{ rank, val[0] });
    }

    try mpi.finalize();
}

The second snippet is more type safe than the first (the first uses *anyopaque everywhere), but feels a lot more verbose

#

This verbosity is needed to to MPI's derived datatypes, allowing strided types (like blocks of 5 f64s separated each by 4 spaces). So, the buffer kind of is meant to encode that. Another solution would be to ditch buffers, take a "naked" slice and only allow "simple types" (bultins like ints or doubles, and structs), and then also still offer the "raw" mpi functions

#

Even if you don't know anything about mpi your input is valuable 🙂

steep tiger
#

... and for context for those interested, what is "MPI"?

verbal dagger
#

What's the point of the kind field? Honestly seems like API could be just T: type, data: []T l, then you can translate T to appropriate MPI type

fleet helm
verbal dagger
fleet helm
verbal dagger
#

How do those work?

fleet helm
#

So you can pass an array, but a datatype can interpret that array as skipping 5 elements for each new element

#

Say you have [1,2,3,4,5,6,7,8]. You can define a new datatype with a stride of 3, and passing that array would send [1, 4, 7]

#

If I was to map []f64 directly, these types would be impossible to make through my api

#

Unless I also add a datatype field, which defeats the whole point of automatically matching the zig type to the mpi type

verbal dagger
#

make a seperate generic type for strided slice which could be recognized in send/recv at comptime

#

so then should use T: type, data: T where T must either be zig slice or fancy slice your lib provides

#

well at that point can just have data: anytype since you'll need manual comptime typechecking anyway

fleet helm
#

Thank you for your input, but I'm still not convinced

#

I will keep thinking

verbal dagger
#

Imo the C interface is so verbose because C has no way to do type introspection or to construct more advanced types. So buf, count and datatype become redundant in zig.

Since the usual way of using MPI is from one codebase, it is fine that library user doesn't have complete control over which exact MPI datatypes are used.

Is there case where one would want to use MPI to communicate with process from other codebase? Don't think it's designed for that