[Phi] fixing device memory creation, implemented AVX copy and fill for
vkCmdCopyBuffers and vkCmdFillBuffer
This commit is contained in:
@@ -235,33 +235,7 @@ To bring forth the driver:
|
|||||||
zig build phi --release=[fast|safe|small]
|
zig build phi --release=[fast|safe|small]
|
||||||
```
|
```
|
||||||
|
|
||||||
Shouldst thou endeavor to forge Phi in the absence of thy Xeon Phi card, thou must permit the emulation of the host:
|
In this manner, the daemon is cross-compiled by way of `k1om-mpss-linux-gcc`, delivered unto its destination via SSH, and speaketh through the SCIF.
|
||||||
|
|
||||||
```
|
|
||||||
zig build phi -Dphi-host-emulation=true --release=[fast|safe|small]
|
|
||||||
```
|
|
||||||
|
|
||||||
Take heed, for this path is forged solely for development; thou shalt find that even the execution of shaders may fail to manifest when thou requirest them most.
|
|
||||||
|
|
||||||
Behold how this creation is wrought: In this state, the daemon is compiled natively by the power of Zig's `std.Build`, and set within `zig-out/bin/phi_device-host`.
|
|
||||||
The driver revealeth but one synthetic Phi device, its voice reaching the daemon through an IPv4 TCP socket tethered only to `127.0.0.1`.
|
|
||||||
For the client socket, thou shalt find it fashioned directly from the `std.Io.net` API; it escheweth the use of C transport functions and requireth no summoning of `libmicmgmt` or `libscif`.
|
|
||||||
|
|
||||||
The driver first endeavoreth to bind itself to a daemon already manifest. If the void remaineth silent, it shall launch its embedded daemon from within, retrying the bond.
|
|
||||||
This transient essence shall vanish from the filesystem once its task is begun. Yet, thou art not bound to this way; thou mayest also start the daemon by thine own hand:
|
|
||||||
|
|
||||||
```
|
|
||||||
./zig-out/bin/phi_device-host
|
|
||||||
```
|
|
||||||
|
|
||||||
The loopback port resideth by default at `43616`, yet thou mayest decree another during the hour of forging, for both driver and daemon alike:
|
|
||||||
|
|
||||||
```
|
|
||||||
zig build phi -Dphi-host-emulation=true -Dphi-emulation-port=43617
|
|
||||||
```
|
|
||||||
|
|
||||||
Shouldst thou forgo the `-Dphi-host-emulation=true` decree, the true path of the Xeon Phi remaineth.
|
|
||||||
In this manner, the daemon is cross-compiled by way of `k1om-mpss-linux-gcc`, delivered unto its destination via SSH/SCP, and speaketh through the SCIF.\
|
|
||||||
|
|
||||||
For those who seek a different method of creation:
|
For those who seek a different method of creation:
|
||||||
|
|
||||||
|
|||||||
@@ -516,29 +516,8 @@ fn customPhi(
|
|||||||
options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path);
|
options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path);
|
||||||
options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix);
|
options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix);
|
||||||
|
|
||||||
const host_emulation = b.option(
|
|
||||||
bool,
|
|
||||||
"phi-host-emulation",
|
|
||||||
"Run the Phi device daemon on the host over a loopback TCP socket (/!\\ Intended for development use only /!\\)",
|
|
||||||
) orelse false;
|
|
||||||
const emulation_port = b.option(
|
|
||||||
u16,
|
|
||||||
"phi-emulation-port",
|
|
||||||
"Loopback TCP port used by Phi host emulation",
|
|
||||||
) orelse 43616;
|
|
||||||
|
|
||||||
options.addOption(bool, "phi_host_emulation", host_emulation);
|
|
||||||
options.addOption(u16, "phi_emulation_port", emulation_port);
|
|
||||||
|
|
||||||
lib_mod.addImport("phi_c", base_c_mod);
|
lib_mod.addImport("phi_c", base_c_mod);
|
||||||
|
|
||||||
if (host_emulation) {
|
|
||||||
lib_mod.addImport("miclib", b.createModule(.{
|
|
||||||
.root_source_file = b.path("src/phi/mic_stub.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
const miclib = b.lazyDependency("miclib", .{
|
const miclib = b.lazyDependency("miclib", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
@@ -546,7 +525,6 @@ fn customPhi(
|
|||||||
}) orelse return error.UnresolvedDependency;
|
}) orelse return error.UnresolvedDependency;
|
||||||
|
|
||||||
lib_mod.addImport("miclib", miclib.module("miclib"));
|
lib_mod.addImport("miclib", miclib.module("miclib"));
|
||||||
}
|
|
||||||
|
|
||||||
const phi_protocol_c = b.addTranslateC(.{
|
const phi_protocol_c = b.addTranslateC(.{
|
||||||
.root_source_file = b.path("src/phi/shared/Protocol.h"),
|
.root_source_file = b.path("src/phi/shared/Protocol.h"),
|
||||||
@@ -578,11 +556,8 @@ fn customPhi(
|
|||||||
"MPSS sysroot path",
|
"MPSS sysroot path",
|
||||||
);
|
);
|
||||||
|
|
||||||
const daemon = try addPhiDaemon(b, optimize, host_emulation, emulation_port, cc, sysroot);
|
const daemon = try addPhiDaemon(b, optimize, cc, sysroot);
|
||||||
const install_daemon = b.addInstallFile(
|
const install_daemon = b.addInstallFile(daemon, "lib/phi_device.mic");
|
||||||
daemon,
|
|
||||||
if (host_emulation) "bin/phi_device-host" else "lib/phi_device.mic",
|
|
||||||
);
|
|
||||||
lib.step.dependOn(&install_daemon.step);
|
lib.step.dependOn(&install_daemon.step);
|
||||||
|
|
||||||
const embedded_daemon = addEmbeddedPhiDaemon(b, daemon);
|
const embedded_daemon = addEmbeddedPhiDaemon(b, daemon);
|
||||||
@@ -591,19 +566,12 @@ fn customPhi(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addPhiDaemon(
|
fn addPhiDaemonCompilerArgs(
|
||||||
|
cmd: *Step.Run,
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
host_emulation: bool,
|
|
||||||
emulation_port: u16,
|
|
||||||
cc: []const u8,
|
|
||||||
sysroot: ?[]const u8,
|
sysroot: ?[]const u8,
|
||||||
) !std.Build.LazyPath {
|
) void {
|
||||||
if (host_emulation)
|
|
||||||
return addPhiHostDaemon(b, optimize, emulation_port);
|
|
||||||
|
|
||||||
const cmd = b.addSystemCommand(&.{cc});
|
|
||||||
|
|
||||||
cmd.addArgs(&.{
|
cmd.addArgs(&.{
|
||||||
"-std=c11",
|
"-std=c11",
|
||||||
"-Wall",
|
"-Wall",
|
||||||
@@ -628,6 +596,11 @@ fn addPhiDaemon(
|
|||||||
.ReleaseFast => cmd.addArgs(&.{ "-O3", "-DNDEBUG" }),
|
.ReleaseFast => cmd.addArgs(&.{ "-O3", "-DNDEBUG" }),
|
||||||
.ReleaseSmall => cmd.addArgs(&.{ "-Os", "-DNDEBUG" }),
|
.ReleaseSmall => cmd.addArgs(&.{ "-Os", "-DNDEBUG" }),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addPhiDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []const u8, sysroot: ?[]const u8) !std.Build.LazyPath {
|
||||||
|
const cmd = b.addSystemCommand(&.{cc});
|
||||||
|
addPhiDaemonCompilerArgs(cmd, b, optimize, sysroot);
|
||||||
|
|
||||||
const sources = [_][]const u8{
|
const sources = [_][]const u8{
|
||||||
"src/phi/mic/main.c",
|
"src/phi/mic/main.c",
|
||||||
@@ -637,53 +610,41 @@ fn addPhiDaemon(
|
|||||||
"src/phi/mic/Logger.c",
|
"src/phi/mic/Logger.c",
|
||||||
"src/phi/mic/Memory.c",
|
"src/phi/mic/Memory.c",
|
||||||
"src/phi/mic/Transport.c",
|
"src/phi/mic/Transport.c",
|
||||||
// Add new files here
|
// Add non-AVX files here
|
||||||
};
|
};
|
||||||
|
|
||||||
for (sources) |source| {
|
for (sources) |source| {
|
||||||
cmd.addFileArg(b.path(source));
|
cmd.addFileArg(b.path(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep KNC AVX-512/IMCI code in separate translation units. This GCC
|
||||||
|
// port must not compile the daemon's scalar/control code with -mavx512f.
|
||||||
|
const avx_sources = [_][]const u8{
|
||||||
|
"src/phi/mic/avx/Copy.c",
|
||||||
|
"src/phi/mic/avx/Fill.c",
|
||||||
|
// Add AVX files here
|
||||||
|
};
|
||||||
|
|
||||||
|
for (avx_sources, 0..) |source, index| {
|
||||||
|
const avx_cmd = b.addSystemCommand(&.{cc});
|
||||||
|
addPhiDaemonCompilerArgs(avx_cmd, b, optimize, sysroot);
|
||||||
|
|
||||||
|
avx_cmd.addArg("-mavx512f");
|
||||||
|
avx_cmd.addArg("-c");
|
||||||
|
avx_cmd.addFileArg(b.path(source));
|
||||||
|
avx_cmd.addArg("-o");
|
||||||
|
|
||||||
|
const avx_object = avx_cmd.addOutputFileArg(
|
||||||
|
b.fmt("phi_avx_{d}.o", .{index}),
|
||||||
|
);
|
||||||
|
|
||||||
|
cmd.addFileArg(avx_object);
|
||||||
|
}
|
||||||
|
|
||||||
cmd.addArgs(&.{ "-lscif", "-o" });
|
cmd.addArgs(&.{ "-lscif", "-o" });
|
||||||
return cmd.addOutputFileArg("phi_device.mic");
|
return cmd.addOutputFileArg("phi_device.mic");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addPhiHostDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, emulation_port: u16) std.Build.LazyPath {
|
|
||||||
const daemon_mod = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = optimize,
|
|
||||||
.link_libc = true,
|
|
||||||
});
|
|
||||||
daemon_mod.addIncludePath(b.path("src/phi/mic"));
|
|
||||||
daemon_mod.addIncludePath(b.path("src/phi/shared"));
|
|
||||||
daemon_mod.addCMacro("PHI_HOST_EMULATION", "1");
|
|
||||||
daemon_mod.addCMacro("PHI_TRANSPORT_PORT", b.fmt("{d}", .{emulation_port}));
|
|
||||||
daemon_mod.addCSourceFiles(.{
|
|
||||||
.files = &.{
|
|
||||||
"src/phi/mic/main.c",
|
|
||||||
"src/phi/mic/Buffer.c",
|
|
||||||
"src/phi/mic/CommandBuffer.c",
|
|
||||||
"src/phi/mic/Daemon.c",
|
|
||||||
"src/phi/mic/Logger.c",
|
|
||||||
"src/phi/mic/Memory.c",
|
|
||||||
"src/phi/mic/Transport.c",
|
|
||||||
},
|
|
||||||
.flags = &.{
|
|
||||||
"-std=c11",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Wno-unused-parameter",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
daemon_mod.linkSystemLibrary("pthread", .{});
|
|
||||||
|
|
||||||
const daemon = b.addExecutable(.{
|
|
||||||
.name = "phi_device-host",
|
|
||||||
.root_module = daemon_mod,
|
|
||||||
});
|
|
||||||
return daemon.getEmittedBin();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn addEmbeddedPhiDaemon(b: *std.Build, daemon: std.Build.LazyPath) std.Build.LazyPath {
|
fn addEmbeddedPhiDaemon(b: *std.Build, daemon: std.Build.LazyPath) std.Build.LazyPath {
|
||||||
const wf = b.addWriteFiles();
|
const wf = b.addWriteFiles();
|
||||||
_ = wf.addCopyFile(daemon, "phi_device.mic");
|
_ = wf.addCopyFile(daemon, "phi_device.mic");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
const base = @import("base");
|
const base = @import("base");
|
||||||
|
const proto = @import("lib.zig").proto;
|
||||||
|
|
||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
|
|
||||||
@@ -31,7 +32,6 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
|||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void {
|
pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements) void {
|
||||||
_ = interface;
|
requirements.alignment = proto.PHI_MEMORY_ALIGNMENT;
|
||||||
_ = requirements;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,9 +120,6 @@ fn appendCommand(self: *Self, comptime T: type, command_type: c_int, payload: T)
|
|||||||
fn remoteMemory(buffer: *base.Buffer) VkError!*PhiDeviceMemory {
|
fn remoteMemory(buffer: *base.Buffer) VkError!*PhiDeviceMemory {
|
||||||
const memory = buffer.memory orelse return VkError.ValidationFailed;
|
const memory = buffer.memory orelse return VkError.ValidationFailed;
|
||||||
const phi_memory: *PhiDeviceMemory = @alignCast(@fieldParentPtr("interface", memory));
|
const phi_memory: *PhiDeviceMemory = @alignCast(@fieldParentPtr("interface", memory));
|
||||||
if (phi_memory.remote_handle == 0) {
|
|
||||||
return VkError.ValidationFailed;
|
|
||||||
}
|
|
||||||
return phi_memory;
|
return phi_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,9 +82,6 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
|
|||||||
|
|
||||||
const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: {
|
const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: {
|
||||||
// If the first connection failed, launch the daemon on the selected device.
|
// If the first connection failed, launch the daemon on the selected device.
|
||||||
if (comptime config.phi_host_emulation)
|
|
||||||
try launchHostDaemon(instance, allocator)
|
|
||||||
else
|
|
||||||
try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num);
|
try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num);
|
||||||
|
|
||||||
const max_connect_attempts = 3;
|
const max_connect_attempts = 3;
|
||||||
@@ -245,39 +242,6 @@ pub fn getDeviceGroupSurfacePresentModesKHR(_: *Interface, _: *base.SurfaceKHR)
|
|||||||
return .{ .local_bit_khr = true };
|
return .{ .local_bit_khr = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn launchHostDaemon(instance: *base.Instance, allocator: std.mem.Allocator) VkError!void {
|
|
||||||
const io = instance.io();
|
|
||||||
const process_id = std.os.linux.getpid();
|
|
||||||
const thread_id = std.Thread.getCurrentId();
|
|
||||||
|
|
||||||
const local_path = std.fmt.allocPrint(allocator, "/tmp/ape_phi_device_{d}_{d}.host", .{ process_id, thread_id }) catch return VkError.OutOfHostMemory;
|
|
||||||
defer allocator.free(local_path);
|
|
||||||
errdefer std.Io.Dir.deleteFileAbsolute(io, local_path) catch |err| {
|
|
||||||
std.log.scoped(.PhiDevice).warn("Failed to remove Phi host daemon after launch error: {s}", .{@errorName(err)});
|
|
||||||
};
|
|
||||||
|
|
||||||
std.Io.Dir.writeFile(.cwd(), io, .{
|
|
||||||
.sub_path = local_path,
|
|
||||||
.data = daemon_binary,
|
|
||||||
}) catch |err| {
|
|
||||||
std.log.scoped(.PhiDevice).err("Failed to write embedded Phi host daemon: {s}", .{@errorName(err)});
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
};
|
|
||||||
|
|
||||||
const launch_command = std.fmt.allocPrint(
|
|
||||||
allocator,
|
|
||||||
"chmod +x {s} && (nohup {s} --unlink-on-start >/tmp/phi_device_host.log 2>&1 </dev/null &)",
|
|
||||||
.{ local_path, local_path },
|
|
||||||
) catch return VkError.OutOfHostMemory;
|
|
||||||
defer allocator.free(launch_command);
|
|
||||||
|
|
||||||
std.log.scoped(.PhiDevice).debug(
|
|
||||||
"Launching Phi host daemon on 127.0.0.1:{d}",
|
|
||||||
.{config.phi_emulation_port},
|
|
||||||
);
|
|
||||||
try runHostCommand(instance, allocator, &.{ "sh", "-c", launch_command });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uploadAndLaunchDaemon(instance: *base.Instance, allocator: std.mem.Allocator, mic_device_num: u32) VkError!void {
|
fn uploadAndLaunchDaemon(instance: *base.Instance, allocator: std.mem.Allocator, mic_device_num: u32) VkError!void {
|
||||||
const io = instance.io();
|
const io = instance.io();
|
||||||
const process_id = std.os.linux.getpid();
|
const process_id = std.os.linux.getpid();
|
||||||
|
|||||||
+110
-36
@@ -13,14 +13,42 @@ const Self = @This();
|
|||||||
pub const Interface = base.DeviceMemory;
|
pub const Interface = base.DeviceMemory;
|
||||||
|
|
||||||
interface: Interface,
|
interface: Interface,
|
||||||
|
|
||||||
remote_handle: u64,
|
remote_handle: u64,
|
||||||
|
scif_offset: ?u64,
|
||||||
|
|
||||||
|
/// Size of the region registered with SCIF.
|
||||||
|
/// This is allocation size rounded up to page size.
|
||||||
|
registered_size: usize,
|
||||||
|
|
||||||
|
/// Bytes exposed through vkMapMemory.
|
||||||
|
/// For HOST_VISIBLE memory this is a slice of host_backing.
|
||||||
data: ?[]u8,
|
data: ?[]u8,
|
||||||
|
|
||||||
|
/// Full page-aligned/page-rounded allocation registered with SCIF.
|
||||||
|
host_backing: ?[]u8,
|
||||||
|
|
||||||
pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self {
|
pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self {
|
||||||
|
if (memory_type_index >= device.interface.physical_device.mem_props.memory_type_count) {
|
||||||
|
return VkError.ValidationFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allocation_size =
|
||||||
|
std.math.cast(usize, size) orelse return VkError.OutOfDeviceMemory;
|
||||||
|
|
||||||
|
const memory_type =
|
||||||
|
device.interface.physical_device.mem_props.memory_types[memory_type_index];
|
||||||
|
|
||||||
|
const host_visible = memory_type.property_flags.host_visible_bit;
|
||||||
|
|
||||||
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
||||||
errdefer allocator.destroy(self);
|
errdefer allocator.destroy(self);
|
||||||
|
|
||||||
var interface = try Interface.init(&device.interface, size, memory_type_index);
|
var interface = try Interface.init(
|
||||||
|
&device.interface,
|
||||||
|
size,
|
||||||
|
memory_type_index,
|
||||||
|
);
|
||||||
|
|
||||||
interface.vtable = &.{
|
interface.vtable = &.{
|
||||||
.destroy = destroy,
|
.destroy = destroy,
|
||||||
@@ -30,68 +58,109 @@ pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceS
|
|||||||
.invalidateRange = invalidateRange,
|
.invalidateRange = invalidateRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (memory_type_index >= device.interface.physical_device.mem_props.memory_type_count) {
|
if (host_visible) {
|
||||||
return VkError.ValidationFailed;
|
const page_size = std.heap.pageSize();
|
||||||
}
|
const registered_size = std.mem.alignForward(usize, allocation_size, page_size);
|
||||||
|
|
||||||
const memory_type = device.interface.physical_device.mem_props.memory_types[memory_type_index];
|
// This needs to be page aligned
|
||||||
const host_visible = memory_type.property_flags.host_visible_bit;
|
const backing = device.interface.device_allocator.allocator().alignedAlloc(u8, .fromByteUnits(std.heap.page_size_max), registered_size) catch return VkError.OutOfHostMemory;
|
||||||
const device_local = memory_type.property_flags.device_local_bit;
|
errdefer device.interface.device_allocator.allocator().free(backing);
|
||||||
const allocation_size = std.math.cast(usize, size) orelse return VkError.OutOfDeviceMemory;
|
|
||||||
|
|
||||||
const remote_handle = if (device_local) blk: {
|
const offset = device.transport.registerHostMemory(backing) catch return VkError.OutOfHostMemory;
|
||||||
const alloc_request: proto.PhiAllocMemoryRequest = .{
|
errdefer device.transport.unregisterHostMemory(offset, backing.len) catch {};
|
||||||
.size = size,
|
|
||||||
.memory_type_index = memory_type_index,
|
const request: proto.PhiMapHostMemoryRequest = .{
|
||||||
.flags = 0,
|
.scif_offset = offset,
|
||||||
|
.scif_size = backing.len,
|
||||||
|
.size = allocation_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
var reply = std.mem.zeroes(proto.PhiAllocMemoryReply);
|
var reply = std.mem.zeroes(proto.PhiNewMemoryReply);
|
||||||
try device.transport.request(proto.PHI_PACKET_ALLOC_MEMORY, std.mem.asBytes(&alloc_request), std.mem.asBytes(&reply));
|
|
||||||
|
try device.transport.request(
|
||||||
|
proto.PHI_PACKET_MAP_HOST_MEMORY,
|
||||||
|
std.mem.asBytes(&request),
|
||||||
|
std.mem.asBytes(&reply),
|
||||||
|
);
|
||||||
|
|
||||||
if (reply.result.status != proto.PHI_STATUS_OK) {
|
if (reply.result.status != proto.PHI_STATUS_OK) {
|
||||||
return PhiTransport.statusToErr(reply.result.status);
|
return PhiTransport.statusToErr(reply.result.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
std.log.scoped(.PhiDeviceMemory).info("Recieved remote handle 0x{X}", .{reply.remote_handle});
|
self.* = .{
|
||||||
|
.interface = interface,
|
||||||
|
.remote_handle = reply.remote_handle,
|
||||||
|
.scif_offset = offset,
|
||||||
|
.registered_size = registered_size,
|
||||||
|
.data = backing[0..allocation_size],
|
||||||
|
.host_backing = backing,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const request: proto.PhiAllocMemoryRequest = .{
|
||||||
|
.size = size,
|
||||||
|
.memory_type_index = memory_type_index,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
break :blk reply.remote_handle;
|
var reply = std.mem.zeroes(proto.PhiNewMemoryReply);
|
||||||
} else 0;
|
|
||||||
errdefer if (remote_handle != 0) self.interface.destroy(allocator);
|
|
||||||
|
|
||||||
const data = if (host_visible)
|
try device.transport.request(
|
||||||
device.interface.device_allocator.allocator().alloc(u8, allocation_size) catch return VkError.OutOfDeviceMemory
|
proto.PHI_PACKET_ALLOC_MEMORY,
|
||||||
else
|
std.mem.asBytes(&request),
|
||||||
null;
|
std.mem.asBytes(&reply),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (reply.result.status != proto.PHI_STATUS_OK) {
|
||||||
|
return PhiTransport.statusToErr(reply.result.status);
|
||||||
|
}
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.interface = interface,
|
.interface = interface,
|
||||||
.remote_handle = remote_handle,
|
.remote_handle = reply.remote_handle,
|
||||||
.data = data,
|
.scif_offset = null,
|
||||||
|
.registered_size = 0,
|
||||||
|
.data = null,
|
||||||
|
.host_backing = null,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
const self: *Self =
|
||||||
const device: *PhiDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
|
@alignCast(@fieldParentPtr("interface", interface));
|
||||||
if (self.data) |data| {
|
|
||||||
interface.owner.device_allocator.allocator().free(data);
|
const device: *PhiDevice =
|
||||||
}
|
@alignCast(@fieldParentPtr("interface", interface.owner));
|
||||||
|
|
||||||
if (self.remote_handle != 0) {
|
if (self.remote_handle != 0) {
|
||||||
const request_payload: proto.PhiFreeMemoryRequest = .{
|
const request_payload: proto.PhiDestroyMemoryRequest = .{
|
||||||
.remote_handle = self.remote_handle,
|
.remote_handle = self.remote_handle,
|
||||||
};
|
};
|
||||||
var reply: proto.PhiFreeMemoryReply = undefined;
|
|
||||||
device.transport.request(proto.PHI_PACKET_FREE_MEMORY, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)) catch |err| {
|
var reply = std.mem.zeroes(proto.PhiResultReply);
|
||||||
std.log.scoped(.PhiTransport).err("Remote free failed: {s}", .{@errorName(err)});
|
|
||||||
|
device.transport.request(proto.PHI_PACKET_DESTROY_MEMORY, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)) catch |err| {
|
||||||
|
std.log.scoped(.PhiDeviceMemory).err("Remote free/unmap failed for handle 0x{X}: {s}", .{ self.remote_handle, @errorName(err) });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (reply.result.status != proto.PHI_STATUS_OK) {
|
if (reply.result.status != proto.PHI_STATUS_OK) {
|
||||||
std.log.scoped(.PhiTransport).err("Remote free returned status {d}", .{reply.result.status});
|
std.log.scoped(.PhiDeviceMemory).err("Remote free/unmap for handle 0x{X} returned status {d}", .{ self.remote_handle, reply.result.status });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.scif_offset) |scif_offset| {
|
||||||
|
device.transport.unregisterHostMemory(scif_offset, self.interface.size) catch |err| {
|
||||||
|
std.log.scoped(.PhiDeviceMemory).err("SCIF unregister failed: {s}", .{@errorName(err)});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.host_backing) |host_backing| {
|
||||||
|
interface.owner.device_allocator.allocator().free(host_backing);
|
||||||
|
}
|
||||||
|
|
||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,19 +178,24 @@ pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.De
|
|||||||
|
|
||||||
pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
|
pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
|
||||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||||
|
|
||||||
const data = self.data orelse return VkError.MemoryMapFailed;
|
const data = self.data orelse return VkError.MemoryMapFailed;
|
||||||
const map_offset = std.math.cast(usize, offset) orelse return VkError.MemoryMapFailed;
|
const map_offset = std.math.cast(usize, offset) orelse return VkError.MemoryMapFailed;
|
||||||
|
|
||||||
if (map_offset >= data.len) {
|
if (map_offset >= data.len) {
|
||||||
return VkError.MemoryMapFailed;
|
return VkError.MemoryMapFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const map_size = if (size == vk.WHOLE_SIZE)
|
const map_size = if (size == vk.WHOLE_SIZE)
|
||||||
data.len - map_offset
|
data.len - map_offset
|
||||||
else
|
else
|
||||||
std.math.cast(usize, size) orelse return VkError.MemoryMapFailed;
|
std.math.cast(usize, size) orelse return VkError.MemoryMapFailed;
|
||||||
|
|
||||||
if (map_size > data.len - map_offset) {
|
if (map_size > data.len - map_offset) {
|
||||||
return VkError.MemoryMapFailed;
|
return VkError.MemoryMapFailed;
|
||||||
}
|
}
|
||||||
return data[map_offset..(map_offset + map_size)];
|
|
||||||
|
return data[map_offset .. map_offset + map_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap(_: *Interface) void {}
|
pub fn unmap(_: *Interface) void {}
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
|
|||||||
self.threaded.deinit();
|
self.threaded.deinit();
|
||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
|
|
||||||
if (comptime !lib.config.phi_host_emulation)
|
|
||||||
mic.unload();
|
mic.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,17 +69,6 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
const physical_device = try PhiPhysicalDevice.createEmulated(allocator, interface);
|
|
||||||
errdefer physical_device.interface.release(allocator) catch @panic("Caught an error while handling an error");
|
|
||||||
|
|
||||||
const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface);
|
|
||||||
errdefer dispatchable.destroy(allocator);
|
|
||||||
|
|
||||||
interface.physical_devices.append(allocator, dispatchable) catch return VkError.OutOfHostMemory;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mic.load() catch |err| {
|
mic.load() catch |err| {
|
||||||
std.log.scoped(.MIC).err("Failed to load libmicmgmt: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to load libmicmgmt: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
|
|||||||
@@ -33,22 +33,7 @@ interface: Interface,
|
|||||||
scif_node_id: u16,
|
scif_node_id: u16,
|
||||||
mic_device_num: u32,
|
mic_device_num: u32,
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: mic.Device, mic_device_num: u32) VkError!*Self {
|
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: ?mic.Device, mic_device_num: u32) VkError!*Self {
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
} else {
|
|
||||||
return createInternal(allocator, instance, mic_device, mic_device_num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn createEmulated(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*Self {
|
|
||||||
if (comptime lib.config.phi_host_emulation)
|
|
||||||
return createInternal(allocator, instance, null, 0)
|
|
||||||
else
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: ?mic.Device, mic_device_num: u32) VkError!*Self {
|
|
||||||
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
||||||
errdefer allocator.destroy(self);
|
errdefer allocator.destroy(self);
|
||||||
|
|
||||||
@@ -76,12 +61,6 @@ fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_de
|
|||||||
|
|
||||||
@memset(interface.props.device_name[0..], 0);
|
@memset(interface.props.device_name[0..], 0);
|
||||||
|
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
interface.props.vendor_id = 0x8086;
|
|
||||||
interface.props.device_id = 0x2250;
|
|
||||||
const name = "Intel(R) Xeon Phi(TM) Coprocessor Host Emulation [Phi ApeDriver]";
|
|
||||||
@memcpy(interface.props.device_name[0..name.len], name);
|
|
||||||
} else {
|
|
||||||
const device = mic_device.?;
|
const device = mic_device.?;
|
||||||
if (device.pciConfig()) |pci_value| {
|
if (device.pciConfig()) |pci_value| {
|
||||||
var pci = pci_value;
|
var pci = pci_value;
|
||||||
@@ -107,7 +86,6 @@ fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_de
|
|||||||
std.log.scoped(.MIC).err("Failed to fetch device PCI config: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to fetch device PCI config: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
interface.props.pipeline_cache_uuid = @splat(0);
|
interface.props.pipeline_cache_uuid = @splat(0);
|
||||||
interface.props.limits = .{
|
interface.props.limits = .{
|
||||||
@@ -248,13 +226,6 @@ fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_de
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface.mem_props.memory_heap_count = 2;
|
interface.mem_props.memory_heap_count = 2;
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
interface.mem_props.memory_heaps[0] = .{
|
|
||||||
.size = std.process.totalSystemMemory() catch 0,
|
|
||||||
.flags = .{ .device_local_bit = true },
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const device = mic_device.?;
|
|
||||||
if (device.memoryInfo()) |memory_value| {
|
if (device.memoryInfo()) |memory_value| {
|
||||||
var memory = memory_value;
|
var memory = memory_value;
|
||||||
defer memory.deinit();
|
defer memory.deinit();
|
||||||
@@ -267,7 +238,6 @@ fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_de
|
|||||||
std.log.scoped(.MIC).err("Failed to fetch device memory infos: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to fetch device memory infos: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
interface.mem_props.memory_heaps[1] = .{
|
interface.mem_props.memory_heaps[1] = .{
|
||||||
.size = std.process.totalSystemMemory() catch 0,
|
.size = std.process.totalSystemMemory() catch 0,
|
||||||
.flags = .{},
|
.flags = .{},
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*bas
|
|||||||
@memcpy(payload[@sizeOf(proto.PhiWorkExecutionRequest)..], phi_command_buffer.commands.items);
|
@memcpy(payload[@sizeOf(proto.PhiWorkExecutionRequest)..], phi_command_buffer.commands.items);
|
||||||
|
|
||||||
// Synchronous queues for now
|
// Synchronous queues for now
|
||||||
var reply = std.mem.zeroes(proto.PhiWorkExecutionReply);
|
var reply = std.mem.zeroes(proto.PhiResultReply);
|
||||||
try device.transport.request(proto.PHI_PACKET_WORK_EXECUTION, payload, std.mem.asBytes(&reply));
|
try device.transport.request(proto.PHI_PACKET_WORK_EXECUTION, payload, std.mem.asBytes(&reply));
|
||||||
|
|
||||||
if (reply.result.status != proto.PHI_STATUS_OK) {
|
if (reply.result.status != proto.PHI_STATUS_OK) {
|
||||||
|
|||||||
+27
-42
@@ -5,7 +5,7 @@ const scif = @import("scif.zig");
|
|||||||
|
|
||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
const proto = lib.proto;
|
const proto = lib.proto;
|
||||||
const Endpoint = if (lib.config.phi_host_emulation) std.Io.net.Stream else scif.epd_t;
|
const Endpoint = scif.epd_t;
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
@@ -15,19 +15,7 @@ mutex: std.Io.Mutex = .init,
|
|||||||
instance: *base.Instance,
|
instance: *base.Instance,
|
||||||
|
|
||||||
pub fn init(instance: *base.Instance, node_id: u16) VkError!Self {
|
pub fn init(instance: *base.Instance, node_id: u16) VkError!Self {
|
||||||
const epd = if (comptime lib.config.phi_host_emulation) blk: {
|
const epd = blk: {
|
||||||
const address: std.Io.net.IpAddress = .{
|
|
||||||
.ip4 = .loopback(lib.config.phi_emulation_port),
|
|
||||||
};
|
|
||||||
const stream = address.connect(instance.io(), .{ .mode = .stream }) catch |err| {
|
|
||||||
std.log.scoped(.PhiTransport).err(
|
|
||||||
"TCP connection to 127.0.0.1:{d} failed: {s}",
|
|
||||||
.{ lib.config.phi_emulation_port, @errorName(err) },
|
|
||||||
);
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
};
|
|
||||||
break :blk stream;
|
|
||||||
} else blk: {
|
|
||||||
try scif.load();
|
try scif.load();
|
||||||
errdefer scif.unload();
|
errdefer scif.unload();
|
||||||
|
|
||||||
@@ -50,8 +38,7 @@ pub fn init(instance: *base.Instance, node_id: u16) VkError!Self {
|
|||||||
break :blk endpoint;
|
break :blk endpoint;
|
||||||
};
|
};
|
||||||
errdefer {
|
errdefer {
|
||||||
closeEndpoint(epd, instance.io());
|
closeEndpoint(epd);
|
||||||
if (comptime !lib.config.phi_host_emulation)
|
|
||||||
scif.unload();
|
scif.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +58,7 @@ pub fn deinit(self: *Self) void {
|
|||||||
std.log.scoped(.PhiTransport).warn("Failed to shut down remote session: {s}", .{@errorName(err)});
|
std.log.scoped(.PhiTransport).warn("Failed to shut down remote session: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
|
||||||
closeEndpoint(self.epd, self.instance.io());
|
closeEndpoint(self.epd);
|
||||||
if (comptime !lib.config.phi_host_emulation)
|
|
||||||
scif.unload();
|
scif.unload();
|
||||||
std.log.scoped(.PhiTransport).info("Closed connection", .{});
|
std.log.scoped(.PhiTransport).info("Closed connection", .{});
|
||||||
}
|
}
|
||||||
@@ -116,21 +102,12 @@ pub fn statusToErr(status: c_int) VkError {
|
|||||||
return switch (status) {
|
return switch (status) {
|
||||||
proto.PHI_STATUS_OUT_OF_MEMORY => VkError.OutOfDeviceMemory,
|
proto.PHI_STATUS_OUT_OF_MEMORY => VkError.OutOfDeviceMemory,
|
||||||
proto.PHI_STATUS_UNSUPPORTED_VERSION => VkError.InitializationFailed,
|
proto.PHI_STATUS_UNSUPPORTED_VERSION => VkError.InitializationFailed,
|
||||||
|
proto.PHI_STATUS_INVALID_ARGUMENT => VkError.ValidationFailed,
|
||||||
else => VkError.Unknown,
|
else => VkError.Unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
var buffer: [0]u8 = .{};
|
|
||||||
var writer = self.epd.writer(self.instance.io(), &buffer);
|
|
||||||
writer.interface.writeAll(bytes) catch |err| {
|
|
||||||
std.log.scoped(.PhiTransport).err("TCP send failed: {s}", .{@errorName(err)});
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
while (offset < bytes.len) {
|
while (offset < bytes.len) {
|
||||||
const written = scif.send(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.send_block);
|
const written = scif.send(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.send_block);
|
||||||
@@ -142,16 +119,6 @@ fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn readAll(self: *Self, bytes: []u8) VkError!void {
|
fn readAll(self: *Self, bytes: []u8) VkError!void {
|
||||||
if (comptime lib.config.phi_host_emulation) {
|
|
||||||
var buffer: [0]u8 = .{};
|
|
||||||
var reader = self.epd.reader(self.instance.io(), &buffer);
|
|
||||||
reader.interface.readSliceAll(bytes) catch |err| {
|
|
||||||
std.log.scoped(.PhiTransport).err("TCP receive failed: {s}", .{@errorName(err)});
|
|
||||||
return VkError.InitializationFailed;
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
while (offset < bytes.len) {
|
while (offset < bytes.len) {
|
||||||
const read = scif.recv(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.recv_block);
|
const read = scif.recv(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.recv_block);
|
||||||
@@ -162,10 +129,7 @@ fn readAll(self: *Self, bytes: []u8) VkError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closeEndpoint(endpoint: Endpoint, io: std.Io) void {
|
fn closeEndpoint(endpoint: Endpoint) void {
|
||||||
if (comptime lib.config.phi_host_emulation)
|
|
||||||
endpoint.close(io)
|
|
||||||
else
|
|
||||||
_ = scif.close(endpoint);
|
_ = scif.close(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,3 +150,24 @@ fn handshake(self: *Self) VkError!void {
|
|||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn registerHostMemory(self: *Self, memory: []u8) VkError!u64 {
|
||||||
|
const offset = scif.register(
|
||||||
|
self.epd,
|
||||||
|
memory.ptr,
|
||||||
|
memory.len,
|
||||||
|
0,
|
||||||
|
@intFromEnum(scif.Prot.read) | @intFromEnum(scif.Prot.write),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
if (offset < 0) {
|
||||||
|
return VkError.Unknown;
|
||||||
|
}
|
||||||
|
return @intCast(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregisterHostMemory(self: *Self, offset: u64, size: usize) VkError!void {
|
||||||
|
if (scif.unregister(self.epd, @intCast(offset), size) != 0) {
|
||||||
|
return VkError.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+51
-7
@@ -1,6 +1,7 @@
|
|||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
|
#include <Memory.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <avx/Avx.h>
|
||||||
|
|
||||||
int PhiIsBufferCommand(const PhiCmdHeader* header)
|
int PhiIsBufferCommand(const PhiCmdHeader* header)
|
||||||
{
|
{
|
||||||
@@ -25,10 +26,13 @@ static PhiStatus CopyBuffer(PhiCommandReader* reader)
|
|||||||
if(command.src_memory == 0 || command.dst_memory == 0)
|
if(command.src_memory == 0 || command.dst_memory == 0)
|
||||||
return PHI_STATUS_INVALID_HANDLE;
|
return PHI_STATUS_INVALID_HANDLE;
|
||||||
|
|
||||||
void* dst = (void*)((uintptr_t)command.dst_memory + (uintptr_t)command.dst_offset);
|
Memory* dst_memory = (Memory*)command.dst_memory;
|
||||||
const void* src = (const void*)((uintptr_t)command.src_memory + (uintptr_t)command.src_offset);
|
const Memory* src_memory = (const Memory*)command.src_memory;
|
||||||
|
|
||||||
memcpy(dst, src, (size_t)command.size);
|
uint8_t* dst = (uint8_t*)dst_memory->ptr + (size_t)command.dst_offset;
|
||||||
|
const uint8_t* src = (const uint8_t*)src_memory->ptr + (size_t)command.src_offset;
|
||||||
|
|
||||||
|
AvxCopy(dst, src, (size_t)command.size);
|
||||||
|
|
||||||
return PHI_STATUS_OK;
|
return PHI_STATUS_OK;
|
||||||
}
|
}
|
||||||
@@ -36,17 +40,57 @@ static PhiStatus CopyBuffer(PhiCommandReader* reader)
|
|||||||
static PhiStatus FillBuffer(PhiCommandReader* reader)
|
static PhiStatus FillBuffer(PhiCommandReader* reader)
|
||||||
{
|
{
|
||||||
PhiCmdFillBuffer command;
|
PhiCmdFillBuffer command;
|
||||||
|
|
||||||
PhiStatus status = PhiReadCommandData(reader, &command, sizeof(command));
|
PhiStatus status = PhiReadCommandData(reader, &command, sizeof(command));
|
||||||
|
|
||||||
if(status != PHI_STATUS_OK)
|
if(status != PHI_STATUS_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if(command.memory == 0)
|
if(command.memory == 0)
|
||||||
return PHI_STATUS_INVALID_HANDLE;
|
return PHI_STATUS_INVALID_HANDLE;
|
||||||
|
|
||||||
uint32_t* dst = (uint32_t*)((uintptr_t)command.memory + (uintptr_t)command.offset);
|
Memory* memory = (Memory*)command.memory;
|
||||||
|
|
||||||
for(; command.size >= 4; command.size -= 4, dst++)
|
uint8_t* dst = (uint8_t*)memory->ptr + (size_t)command.offset;
|
||||||
*dst = command.data;
|
|
||||||
|
size_t size = (size_t)command.size;
|
||||||
|
const uint32_t value = command.data;
|
||||||
|
|
||||||
|
// Check if dst and size are 4-byte aligned
|
||||||
|
if((((uintptr_t)dst | size) & 3) != 0)
|
||||||
|
return PHI_STATUS_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
// Bring dst to a 64-byte cache-line boundary.
|
||||||
|
while(size >= 4 && ((uintptr_t)dst & 63) != 0)
|
||||||
|
{
|
||||||
|
*(uint32_t*)dst = value;
|
||||||
|
|
||||||
|
dst += 4;
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(size >= 256)
|
||||||
|
{
|
||||||
|
AvxFill256(dst, value);
|
||||||
|
|
||||||
|
dst += 256;
|
||||||
|
size -= 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(size >= 64)
|
||||||
|
{
|
||||||
|
AvxFill64(dst, value);
|
||||||
|
|
||||||
|
dst += 64;
|
||||||
|
size -= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* tail = (uint32_t*)dst;
|
||||||
|
while(size >= 4)
|
||||||
|
{
|
||||||
|
*tail++ = value;
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
return PHI_STATUS_OK;
|
return PHI_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static PhiStatus ExecuteCommand(PhiCommandReader* reader, const PhiCmdHeader* co
|
|||||||
int HandleWorkExecution(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
int HandleWorkExecution(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiWorkExecutionRequest request;
|
PhiWorkExecutionRequest request;
|
||||||
PhiWorkExecutionReply reply = {
|
PhiResultReply reply = {
|
||||||
.result = {
|
.result = {
|
||||||
.status = PHI_STATUS_OK,
|
.status = PHI_STATUS_OK,
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Protocol.h"
|
||||||
#include <CommandBuffer.h>
|
#include <CommandBuffer.h>
|
||||||
#include <Daemon.h>
|
#include <Daemon.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
@@ -75,13 +76,14 @@ int HandlePacket(PhiEndpoint endpoint)
|
|||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PHI_PACKET_MAP_HOST_MEMORY:
|
||||||
case PHI_PACKET_ALLOC_MEMORY:
|
case PHI_PACKET_ALLOC_MEMORY:
|
||||||
if(HandleAllocMemory(endpoint, &header) < 0)
|
if(HandleNewMemory(endpoint, &header) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PHI_PACKET_FREE_MEMORY:
|
case PHI_PACKET_DESTROY_MEMORY:
|
||||||
if(HandleFreeMemory(endpoint, &header) < 0)
|
if(HandleDestroyMemory(endpoint, &header) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ int SendReply(PhiEndpoint endpoint, const PhiMessageHeader* request, const void*
|
|||||||
|
|
||||||
int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status)
|
int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status)
|
||||||
{
|
{
|
||||||
PhiFreeMemoryReply reply = {
|
PhiResultReply reply = {
|
||||||
.result = {
|
.result = {
|
||||||
.status = status,
|
.status = status,
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
|
|||||||
+91
-18
@@ -1,12 +1,60 @@
|
|||||||
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
static size_t AlignUp(size_t value, size_t alignment)
|
||||||
{
|
{
|
||||||
PhiAllocMemoryRequest request;
|
return (value + alignment - 1) & ~(alignment - 1);
|
||||||
PhiAllocMemoryReply reply = {
|
}
|
||||||
|
|
||||||
|
static Memory* MapHostMemory(PhiEndpoint epd, const PhiMapHostMemoryRequest* request)
|
||||||
|
{
|
||||||
|
void* ptr = scif_mmap(NULL, request->scif_size, PROT_READ | PROT_WRITE, 0, epd, request->scif_offset);
|
||||||
|
|
||||||
|
if(ptr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
PhiLogErrorFmt("Failed to map host memory: %s", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory* memory = malloc(sizeof(*memory));
|
||||||
|
if(!memory)
|
||||||
|
{
|
||||||
|
scif_munmap(ptr, request->scif_size);
|
||||||
|
PhiLogError("Failed to allocate memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory->type = PHI_MEMORY_HOST_MAPPED;
|
||||||
|
memory->ptr = ptr;
|
||||||
|
memory->size = request->size;
|
||||||
|
memory->scif_size = request->scif_size;
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Memory* AllocMemory(PhiEndpoint epd, const PhiAllocMemoryRequest* request)
|
||||||
|
{
|
||||||
|
Memory* memory = (Memory*)malloc(sizeof(Memory) + PHI_MEMORY_ALIGNMENT + request->size);
|
||||||
|
|
||||||
|
if(!memory)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memory->type = PHI_MEMORY_LOCAL;
|
||||||
|
memory->ptr = (void*)AlignUp((uintptr_t)memory + sizeof(Memory), PHI_MEMORY_ALIGNMENT);
|
||||||
|
memory->size = request->size;
|
||||||
|
memory->scif_size = 0;
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HandleNewMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
|
{
|
||||||
|
PhiNewMemoryReply reply = {
|
||||||
.result = {
|
.result = {
|
||||||
.status = PHI_STATUS_OK,
|
.status = PHI_STATUS_OK,
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
@@ -15,37 +63,54 @@ int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
|||||||
.size = 0,
|
.size = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if(header->payload_size != sizeof(request))
|
if(header->payload_size != sizeof(PhiAllocMemoryRequest) && header->payload_size != sizeof(PhiMapHostMemoryRequest))
|
||||||
{
|
{
|
||||||
if(DrainPayload(endpoint, header->payload_size) < 0)
|
if(DrainPayload(endpoint, header->payload_size) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
reply.result.status = PHI_STATUS_BAD_MESSAGE;
|
reply.result.status = PHI_STATUS_BAD_MESSAGE;
|
||||||
return SendReply(endpoint, header, &reply, sizeof(reply));
|
return SendReply(endpoint, header, &reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Memory* memory;
|
||||||
|
|
||||||
|
if(header->type == PHI_PACKET_ALLOC_MEMORY)
|
||||||
|
{
|
||||||
|
PhiAllocMemoryRequest request;
|
||||||
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
|
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
memory = AllocMemory(endpoint, &request);
|
||||||
const void* memory = malloc((size_t)request.size);
|
|
||||||
|
|
||||||
if(memory == NULL)
|
if(memory == NULL)
|
||||||
{
|
PhiLogErrorFmt("Failed to allocate %zu bytes", (size_t)request.size);
|
||||||
reply.result.status = PHI_STATUS_OUT_OF_MEMORY;
|
|
||||||
PhiLogInfoFmt("Failed to allocate %zu bytes", (size_t)request.size);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
PhiLogInfoFmt("Allocated %llu bytes to handle 0x%X", request.size, (uintptr_t)memory);
|
||||||
|
}
|
||||||
|
else if(header->type == PHI_PACKET_MAP_HOST_MEMORY)
|
||||||
|
{
|
||||||
|
PhiMapHostMemoryRequest request;
|
||||||
|
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
|
||||||
|
return -1;
|
||||||
|
memory = MapHostMemory(endpoint, &request);
|
||||||
|
if(memory == NULL)
|
||||||
|
reply.result.status = PHI_STATUS_MAP_HOST_MEMORY_FAILED;
|
||||||
|
else
|
||||||
|
PhiLogInfoFmt("Mapped host memory to handle 0x%X", (uint64_t)(uintptr_t)memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory != NULL)
|
||||||
{
|
{
|
||||||
reply.remote_handle = (uint64_t)(uintptr_t)memory;
|
reply.remote_handle = (uint64_t)(uintptr_t)memory;
|
||||||
reply.size = request.size;
|
reply.size = memory->size;
|
||||||
PhiLogInfoFmt("Allocated %llu bytes to handle 0x%X", reply.size, reply.remote_handle);
|
|
||||||
}
|
}
|
||||||
|
else if(reply.result.status == PHI_STATUS_OK)
|
||||||
|
reply.result.status = PHI_STATUS_OUT_OF_MEMORY;
|
||||||
|
|
||||||
return SendReply(endpoint, header, &reply, sizeof(reply));
|
return SendReply(endpoint, header, &reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
int HandleDestroyMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiFreeMemoryRequest request;
|
PhiDestroyMemoryRequest request;
|
||||||
PhiFreeMemoryReply reply = {
|
PhiResultReply reply = {
|
||||||
.result = {
|
.result = {
|
||||||
.status = PHI_STATUS_OK,
|
.status = PHI_STATUS_OK,
|
||||||
.reserved = 0,
|
.reserved = 0,
|
||||||
@@ -70,8 +135,16 @@ int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free((void*)(uintptr_t)request.remote_handle);
|
const Memory* memory = (const Memory*)(uintptr_t)request.remote_handle;
|
||||||
PhiLogInfoFmt("Freed memory handle 0x%X", request.remote_handle);
|
|
||||||
|
if(memory->type == PHI_MEMORY_LOCAL)
|
||||||
|
free((void*)memory);
|
||||||
|
else if(memory->type == PHI_MEMORY_HOST_MAPPED)
|
||||||
|
scif_munmap((void*)memory->ptr, memory->size);
|
||||||
|
|
||||||
|
PhiLogInfoFmt("Destroyed %s memory handle 0x%X",
|
||||||
|
memory->type == PHI_MEMORY_LOCAL ? "local" : "host-mapped",
|
||||||
|
request.remote_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SendReply(endpoint, header, &reply, sizeof(reply));
|
return SendReply(endpoint, header, &reply, sizeof(reply));
|
||||||
|
|||||||
+20
-2
@@ -3,7 +3,25 @@
|
|||||||
|
|
||||||
#include <Daemon.h>
|
#include <Daemon.h>
|
||||||
|
|
||||||
int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
typedef enum MemoryType
|
||||||
int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
{
|
||||||
|
PHI_MEMORY_LOCAL,
|
||||||
|
PHI_MEMORY_HOST_MAPPED,
|
||||||
|
} MemoryType;
|
||||||
|
|
||||||
|
typedef struct Memory
|
||||||
|
{
|
||||||
|
MemoryType type;
|
||||||
|
|
||||||
|
void* ptr;
|
||||||
|
|
||||||
|
uint64_t size;
|
||||||
|
uint64_t scif_size;
|
||||||
|
|
||||||
|
off_t scif_offset;
|
||||||
|
} Memory;
|
||||||
|
|
||||||
|
int HandleNewMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
||||||
|
int HandleDestroyMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,73 +1,5 @@
|
|||||||
#include <Transport.h>
|
#include <Transport.h>
|
||||||
|
|
||||||
#ifdef PHI_HOST_EMULATION
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static struct sockaddr_in PhiLoopbackAddress(uint16_t port)
|
|
||||||
{
|
|
||||||
struct sockaddr_in address = {
|
|
||||||
.sin_family = AF_INET,
|
|
||||||
.sin_port = htons(port),
|
|
||||||
.sin_addr = {
|
|
||||||
.s_addr = htonl(INADDR_LOOPBACK),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint)
|
|
||||||
{
|
|
||||||
return accept(endpoint, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int PhiTransportClose(PhiEndpoint endpoint)
|
|
||||||
{
|
|
||||||
return close(endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
PhiEndpoint PhiTransportListen(uint16_t port)
|
|
||||||
{
|
|
||||||
PhiEndpoint endpoint = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if(endpoint == PHI_ENDPOINT_INVALID)
|
|
||||||
return PHI_ENDPOINT_INVALID;
|
|
||||||
|
|
||||||
const int reuse_address = 1;
|
|
||||||
if(setsockopt(endpoint, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address)) < 0)
|
|
||||||
{
|
|
||||||
PhiTransportClose(endpoint);
|
|
||||||
return PHI_ENDPOINT_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct sockaddr_in address = PhiLoopbackAddress(port);
|
|
||||||
if(bind(endpoint, (const struct sockaddr*)&address, sizeof(address)) < 0 || listen(endpoint, 16) < 0)
|
|
||||||
{
|
|
||||||
PhiTransportClose(endpoint);
|
|
||||||
return PHI_ENDPOINT_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size)
|
|
||||||
{
|
|
||||||
return recv(endpoint, data, size, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size)
|
|
||||||
{
|
|
||||||
#ifdef MSG_NOSIGNAL
|
|
||||||
return send(endpoint, data, size, MSG_NOSIGNAL);
|
|
||||||
#else
|
|
||||||
return send(endpoint, data, size, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint)
|
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint)
|
||||||
{
|
{
|
||||||
struct scif_portID peer;
|
struct scif_portID peer;
|
||||||
@@ -105,5 +37,3 @@ ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size)
|
|||||||
{
|
{
|
||||||
return scif_send(endpoint, (void*)data, size, SCIF_SEND_BLOCK);
|
return scif_send(endpoint, (void*)data, size, SCIF_SEND_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -5,12 +5,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifdef PHI_HOST_EMULATION
|
|
||||||
typedef int PhiEndpoint;
|
|
||||||
#else
|
|
||||||
#include <scif.h>
|
#include <scif.h>
|
||||||
typedef scif_epd_t PhiEndpoint;
|
typedef scif_epd_t PhiEndpoint;
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PHI_ENDPOINT_INVALID ((PhiEndpoint) - 1)
|
#define PHI_ENDPOINT_INVALID ((PhiEndpoint) - 1)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef APE_PHI_AVX_H
|
||||||
|
#define APE_PHI_AVX_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void AvxCopy(uint8_t* dst, const uint8_t* src, size_t size);
|
||||||
|
|
||||||
|
void AvxFill64(void* dst, uint32_t value);
|
||||||
|
void AvxFill256(void* dst, uint32_t value);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include <immintrin.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define PHI_CACHE_LINE_SIZE 64
|
||||||
|
|
||||||
|
static inline __m512i Load512KNC(const uint8_t* src)
|
||||||
|
{
|
||||||
|
return _mm512_load_epi32((const void*)src);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvxCopy(uint8_t* dst, const uint8_t* src, size_t size)
|
||||||
|
{
|
||||||
|
if(size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Generic fallback if not 4-byte aligned
|
||||||
|
if((((uintptr_t)dst | (uintptr_t)src | size) & 3) != 0)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align the destination to 64 bytes.
|
||||||
|
size_t prefix = (-(uintptr_t)dst) & (PHI_CACHE_LINE_SIZE - 1);
|
||||||
|
|
||||||
|
if(prefix > size)
|
||||||
|
prefix = size;
|
||||||
|
|
||||||
|
if(prefix != 0)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, prefix);
|
||||||
|
|
||||||
|
dst += prefix;
|
||||||
|
src += prefix;
|
||||||
|
size -= prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(((uintptr_t)src & (PHI_CACHE_LINE_SIZE - 1)) == 0)
|
||||||
|
{
|
||||||
|
// Unroll four cache lines at a time
|
||||||
|
while(size >= 256)
|
||||||
|
{
|
||||||
|
const __m512i v0 = _mm512_load_epi32((const void*)(src + 0));
|
||||||
|
const __m512i v1 = _mm512_load_epi32((const void*)(src + 64));
|
||||||
|
const __m512i v2 = _mm512_load_epi32((const void*)(src + 128));
|
||||||
|
const __m512i v3 = _mm512_load_epi32((const void*)(src + 192));
|
||||||
|
|
||||||
|
_mm512_store_epi32((void*)(dst + 0), v0);
|
||||||
|
_mm512_store_epi32((void*)(dst + 64), v1);
|
||||||
|
_mm512_store_epi32((void*)(dst + 128), v2);
|
||||||
|
_mm512_store_epi32((void*)(dst + 192), v3);
|
||||||
|
|
||||||
|
src += 256;
|
||||||
|
dst += 256;
|
||||||
|
size -= 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(size >= 64)
|
||||||
|
{
|
||||||
|
const __m512i value = _mm512_load_epi32((const void*)src);
|
||||||
|
|
||||||
|
_mm512_store_epi32((void*)dst, value);
|
||||||
|
|
||||||
|
src += 64;
|
||||||
|
dst += 64;
|
||||||
|
size -= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Source is only 4-byte aligned.
|
||||||
|
// KNC's loadunpack pair implements the conceptual unaligned 64-byte load.
|
||||||
|
while(size >= 256)
|
||||||
|
{
|
||||||
|
const __m512i v0 = Load512KNC(src + 0);
|
||||||
|
const __m512i v1 = Load512KNC(src + 64);
|
||||||
|
const __m512i v2 = Load512KNC(src + 128);
|
||||||
|
const __m512i v3 = Load512KNC(src + 192);
|
||||||
|
|
||||||
|
_mm512_store_epi32((void*)(dst + 0), v0);
|
||||||
|
_mm512_store_epi32((void*)(dst + 64), v1);
|
||||||
|
_mm512_store_epi32((void*)(dst + 128), v2);
|
||||||
|
_mm512_store_epi32((void*)(dst + 192), v3);
|
||||||
|
|
||||||
|
src += 256;
|
||||||
|
dst += 256;
|
||||||
|
size -= 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(size >= 64)
|
||||||
|
{
|
||||||
|
const __m512i value = Load512KNC(src);
|
||||||
|
|
||||||
|
_mm512_store_epi32((void*)dst, value);
|
||||||
|
|
||||||
|
src += 64;
|
||||||
|
dst += 64;
|
||||||
|
size -= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At most 63 bytes remain
|
||||||
|
if(size != 0)
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <immintrin.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Dst must be 64-byte aligned
|
||||||
|
void PhiFill256KNC(void* dst, uint32_t value)
|
||||||
|
{
|
||||||
|
__m512i v = _mm512_set1_epi32((int)value);
|
||||||
|
|
||||||
|
uint8_t* d = (uint8_t*)dst;
|
||||||
|
|
||||||
|
_mm512_store_epi32((void*)(d + 0), v);
|
||||||
|
_mm512_store_epi32((void*)(d + 64), v);
|
||||||
|
_mm512_store_epi32((void*)(d + 128), v);
|
||||||
|
_mm512_store_epi32((void*)(d + 192), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dst must be 64-byte aligned
|
||||||
|
void PhiFill64KNC(void* dst, uint32_t value)
|
||||||
|
{
|
||||||
|
__m512i v = _mm512_set1_epi32((int)value);
|
||||||
|
|
||||||
|
_mm512_store_epi32(dst, v);
|
||||||
|
}
|
||||||
@@ -2,11 +2,6 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef PHI_HOST_EMULATION
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <Daemon.h>
|
#include <Daemon.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
|
|
||||||
@@ -21,13 +16,8 @@ static void* HandleClient(void* const argument)
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
#ifdef PHI_HOST_EMULATION
|
|
||||||
if(argc == 2 && strcmp(argv[1], "--unlink-on-start") == 0)
|
|
||||||
(void)unlink(argv[0]);
|
|
||||||
#else
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
#endif
|
|
||||||
|
|
||||||
PhiEndpoint endpoint = StartDaemon();
|
PhiEndpoint endpoint = StartDaemon();
|
||||||
pthread_attr_t client_thread_attributes;
|
pthread_attr_t client_thread_attributes;
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
pub const Device = struct {};
|
|
||||||
|
|
||||||
pub fn unload() void {}
|
|
||||||
@@ -6,22 +6,8 @@ const PciInfo = struct {
|
|||||||
/// Not a hashmap as they need runtime allocations
|
/// Not a hashmap as they need runtime allocations
|
||||||
pub const map = [_]PciInfo{
|
pub const map = [_]PciInfo{
|
||||||
.{ .id = 0x2250, .name = "Intel(R) Xeon Phi(TM) Coprocessor 5100 Series" },
|
.{ .id = 0x2250, .name = "Intel(R) Xeon Phi(TM) Coprocessor 5100 Series" },
|
||||||
|
|
||||||
.{ .id = 0x2251, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2252, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2253, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2254, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2255, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2256, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2257, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2258, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x2259, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x225a, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
.{ .id = 0x225b, .name = "Intel(R) Xeon Phi(TM) Coprocessor x100 Series" },
|
|
||||||
|
|
||||||
.{ .id = 0x225c, .name = "Intel(R) Xeon Phi(TM) Coprocessor SE10/7120 Series" },
|
.{ .id = 0x225c, .name = "Intel(R) Xeon Phi(TM) Coprocessor SE10/7120 Series" },
|
||||||
.{ .id = 0x225d, .name = "Intel(R) Xeon Phi(TM) Coprocessor 3120 Series" },
|
.{ .id = 0x225d, .name = "Intel(R) Xeon Phi(TM) Coprocessor 3120 Series" },
|
||||||
.{ .id = 0x225e, .name = "Intel(R) Xeon Phi(TM) Coprocessor 31S1" },
|
.{ .id = 0x225e, .name = "Intel(R) Xeon Phi(TM) Coprocessor 31S1" },
|
||||||
|
|
||||||
.{ .id = 0x2262, .name = "Intel(R) Xeon Phi(TM) Coprocessor 7220" },
|
.{ .id = 0x2262, .name = "Intel(R) Xeon Phi(TM) Coprocessor 7220" },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ pub const PortId = extern struct {
|
|||||||
port: u16,
|
port: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Prot = enum(c_int) {
|
||||||
|
read = 1 << 0,
|
||||||
|
write = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
pub const send_block = 1;
|
pub const send_block = 1;
|
||||||
pub const recv_block = 1;
|
pub const recv_block = 1;
|
||||||
|
|
||||||
@@ -23,6 +28,10 @@ var scif_connect: *const fn (epd: epd_t, dst: *const PortId) callconv(.c) c_int
|
|||||||
var scif_send: *const fn (epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
|
var scif_send: *const fn (epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
|
||||||
// SAFETY: load assigns every function pointer before the public wrappers can be used.
|
// SAFETY: load assigns every function pointer before the public wrappers can be used.
|
||||||
var scif_recv: *const fn (epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
|
var scif_recv: *const fn (epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
|
||||||
|
// SAFETY: load assigns every function pointer before the public wrappers can be used.
|
||||||
|
var scif_register: *const fn (epd: epd_t, addr: ?*anyopaque, len: usize, offset: i64, prot_flags: c_int, map_flags: c_int) callconv(.c) i64 = undefined;
|
||||||
|
// SAFETY: load assigns every function pointer before the public wrappers can be used.
|
||||||
|
var scif_unregister: *const fn (epd: epd_t, offset: i64, len: usize) callconv(.c) c_int = undefined;
|
||||||
|
|
||||||
// SAFETY: load initializes the module before it can be closed or queried.
|
// SAFETY: load initializes the module before it can be closed or queried.
|
||||||
var module: std.DynLib = undefined;
|
var module: std.DynLib = undefined;
|
||||||
@@ -49,6 +58,8 @@ pub fn load() VkError!void {
|
|||||||
scif_connect = module.lookup(@TypeOf(scif_connect), "scif_connect") orelse return VkError.InitializationFailed;
|
scif_connect = module.lookup(@TypeOf(scif_connect), "scif_connect") orelse return VkError.InitializationFailed;
|
||||||
scif_send = module.lookup(@TypeOf(scif_send), "scif_send") orelse return VkError.InitializationFailed;
|
scif_send = module.lookup(@TypeOf(scif_send), "scif_send") orelse return VkError.InitializationFailed;
|
||||||
scif_recv = module.lookup(@TypeOf(scif_recv), "scif_recv") orelse return VkError.InitializationFailed;
|
scif_recv = module.lookup(@TypeOf(scif_recv), "scif_recv") orelse return VkError.InitializationFailed;
|
||||||
|
scif_register = module.lookup(@TypeOf(scif_register), "scif_register") orelse return VkError.InitializationFailed;
|
||||||
|
scif_unregister = module.lookup(@TypeOf(scif_unregister), "scif_unregister") orelse return VkError.InitializationFailed;
|
||||||
|
|
||||||
_ = ref_count.fetchAdd(1, .monotonic);
|
_ = ref_count.fetchAdd(1, .monotonic);
|
||||||
}
|
}
|
||||||
@@ -81,3 +92,11 @@ pub inline fn send(epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int)
|
|||||||
pub inline fn recv(epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) isize {
|
pub inline fn recv(epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) isize {
|
||||||
return scif_recv(epd, msg, len, flags);
|
return scif_recv(epd, msg, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn register(epd: epd_t, addr: ?*anyopaque, len: usize, offset: i64, prot_flags: c_int, map_flags: c_int) i64 {
|
||||||
|
return scif_register(epd, addr, len, offset, prot_flags, map_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn unregister(epd: epd_t, offset: i64, len: usize) c_int {
|
||||||
|
return scif_unregister(epd, offset, len);
|
||||||
|
}
|
||||||
|
|||||||
+22
-15
@@ -4,6 +4,8 @@
|
|||||||
#include "Commands.h" // IWYU pragma: keep
|
#include "Commands.h" // IWYU pragma: keep
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PHI_MEMORY_ALIGNMENT 64
|
||||||
|
|
||||||
#define PHI_PROTOCOL_MAGIC 0x50484941u
|
#define PHI_PROTOCOL_MAGIC 0x50484941u
|
||||||
#define PHI_PROTOCOL_VERSION 1u
|
#define PHI_PROTOCOL_VERSION 1u
|
||||||
#define PHI_SCIF_PORT 43616u
|
#define PHI_SCIF_PORT 43616u
|
||||||
@@ -16,11 +18,12 @@ typedef enum PhiPacketType
|
|||||||
{
|
{
|
||||||
PHI_PACKET_HELLO = 1,
|
PHI_PACKET_HELLO = 1,
|
||||||
PHI_PACKET_ALLOC_MEMORY = 2,
|
PHI_PACKET_ALLOC_MEMORY = 2,
|
||||||
PHI_PACKET_FREE_MEMORY = 3,
|
PHI_PACKET_DESTROY_MEMORY = 3,
|
||||||
PHI_PACKET_UPLOAD = 4,
|
PHI_PACKET_UPLOAD = 4,
|
||||||
PHI_PACKET_DOWNLOAD = 5,
|
PHI_PACKET_DOWNLOAD = 5,
|
||||||
PHI_PACKET_WORK_EXECUTION = 6,
|
PHI_PACKET_WORK_EXECUTION = 6,
|
||||||
PHI_PACKET_SHUTDOWN = 7,
|
PHI_PACKET_SHUTDOWN = 7,
|
||||||
|
PHI_PACKET_MAP_HOST_MEMORY = 8,
|
||||||
} PhiPacketType;
|
} PhiPacketType;
|
||||||
|
|
||||||
typedef enum PhiStatus
|
typedef enum PhiStatus
|
||||||
@@ -31,6 +34,8 @@ typedef enum PhiStatus
|
|||||||
PHI_STATUS_UNSUPPORTED_PACKET = 3,
|
PHI_STATUS_UNSUPPORTED_PACKET = 3,
|
||||||
PHI_STATUS_OUT_OF_MEMORY = 4,
|
PHI_STATUS_OUT_OF_MEMORY = 4,
|
||||||
PHI_STATUS_INVALID_HANDLE = 5,
|
PHI_STATUS_INVALID_HANDLE = 5,
|
||||||
|
PHI_STATUS_MAP_HOST_MEMORY_FAILED = 6,
|
||||||
|
PHI_STATUS_INVALID_ARGUMENT = 7,
|
||||||
} PhiStatus;
|
} PhiStatus;
|
||||||
|
|
||||||
typedef struct PhiMessageHeader
|
typedef struct PhiMessageHeader
|
||||||
@@ -48,6 +53,11 @@ typedef struct PhiResult
|
|||||||
uint32_t reserved;
|
uint32_t reserved;
|
||||||
} PhiResult;
|
} PhiResult;
|
||||||
|
|
||||||
|
typedef struct PhiResultReply
|
||||||
|
{
|
||||||
|
PhiResult result;
|
||||||
|
} PhiResultReply;
|
||||||
|
|
||||||
typedef struct PhiHelloRequest
|
typedef struct PhiHelloRequest
|
||||||
{
|
{
|
||||||
uint32_t host_protocol_version;
|
uint32_t host_protocol_version;
|
||||||
@@ -68,22 +78,24 @@ typedef struct PhiAllocMemoryRequest
|
|||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
} PhiAllocMemoryRequest;
|
} PhiAllocMemoryRequest;
|
||||||
|
|
||||||
typedef struct PhiAllocMemoryReply
|
typedef struct PhiNewMemoryReply
|
||||||
{
|
{
|
||||||
PhiResult result;
|
PhiResult result;
|
||||||
uint64_t remote_handle;
|
uint64_t remote_handle;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
} PhiAllocMemoryReply;
|
} PhiNewMemoryReply;
|
||||||
|
|
||||||
typedef struct PhiFreeMemoryRequest
|
typedef struct PhiMapHostMemoryRequest
|
||||||
|
{
|
||||||
|
uint64_t scif_offset;
|
||||||
|
uint64_t scif_size;
|
||||||
|
uint64_t size;
|
||||||
|
} PhiMapHostMemoryRequest;
|
||||||
|
|
||||||
|
typedef struct PhiDestroyMemoryRequest
|
||||||
{
|
{
|
||||||
uint64_t remote_handle;
|
uint64_t remote_handle;
|
||||||
} PhiFreeMemoryRequest;
|
} PhiDestroyMemoryRequest;
|
||||||
|
|
||||||
typedef struct PhiFreeMemoryReply
|
|
||||||
{
|
|
||||||
PhiResult result;
|
|
||||||
} PhiFreeMemoryReply;
|
|
||||||
|
|
||||||
typedef struct PhiWorkExecutionRequest
|
typedef struct PhiWorkExecutionRequest
|
||||||
{
|
{
|
||||||
@@ -91,9 +103,4 @@ typedef struct PhiWorkExecutionRequest
|
|||||||
uint64_t command_buffer_size;
|
uint64_t command_buffer_size;
|
||||||
} PhiWorkExecutionRequest;
|
} PhiWorkExecutionRequest;
|
||||||
|
|
||||||
typedef struct PhiWorkExecutionReply
|
|
||||||
{
|
|
||||||
PhiResult result;
|
|
||||||
} PhiWorkExecutionReply;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user