Fixed some bugs & added some optimizations for single threaded

Removed old run_tests.sh & added benchmark.sh
This commit is contained in:
Caleb J. Gardner
2026-06-03 21:53:31 -05:00
parent 6311553c55
commit 62f98cccaf
7 changed files with 59 additions and 89 deletions
Executable
+17
View File
@@ -0,0 +1,17 @@
#! /usr/bin/env bash
ARCHIVE="testing/LinuxPATest.sfs"
REF_EXT_LOC="testing/LinuxPAReference"
PROG_EXT_LOC="testing/LinuxPABinTest"
echo "Testing Multi-threaded Performance"
echo ""
hyperfine --warmup 5 --prepare "rm -rf $REF_EXT_LOC && rm -rf $PROG_EXT_LOC" "unsquashfs -d $REF_EXT_LOC $ARCHIVE" "zig-out/bin/unsquashfs -d $PROG_EXT_LOC $ARCHIVE"
echo ""
echo "Testing Single-threaded Performance"
echo ""
hyperfine --warmup 5 --prepare "rm -rf $REF_EXT_LOC && rm -rf $PROG_EXT_LOC" "unsquashfs -p 1 -d $REF_EXT_LOC $ARCHIVE" "zig-out/bin/unsquashfs -p 1 -d $PROG_EXT_LOC $ARCHIVE"
-10
View File
@@ -1,10 +0,0 @@
#!/bin/sh
zig test \
-lc \
-lz \
-llzma \
-lminilzo \
-llz4 \
-lzstd \
src/test.zig
+4 -3
View File
@@ -83,7 +83,8 @@ pub fn extract(self: *Archive, alloc: std.mem.Allocator, io: Io, ext_loc: []cons
self.super.block_size,
self.super.root_ref,
);
return Extract.extract(alloc, io, root_inode, &self.cache, self.super, ext_loc, options);
return Extract.extractSingleThreaded(alloc, io, root_inode, &self.cache, self.super, ext_loc, options);
}
// Superblock
@@ -126,12 +127,12 @@ pub const Superblock = extern struct {
pub fn validate(self: Superblock) !void {
if (self.magic != std.mem.readInt(u32, "hsqs", .little))
return error.BadMagic;
if (self.flags.check)
return error.BadCheckFlag;
if (self.ver_maj != 4 or self.ver_min != 0)
return error.InvalidVersion;
if (self.block_log != std.math.log2(self.block_size))
return error.BadBlockLog;
if (self.flags.check)
return error.BadCheckFlag;
}
};
+2 -2
View File
@@ -48,7 +48,7 @@ pub fn init(io: Io, cache: *DecompCache, block_size: u32, size: u64, start: u64,
};
}
pub fn deinit(self: Reader) void {
self.cache.finished(self.io);
self.cache.finished(self.io, self.cur_offset);
}
pub fn addFragment(self: *Reader, data: []u8, offset: u32) void {
@@ -98,7 +98,7 @@ fn advance(self: *Reader) Io.Reader.Error!void {
self.interface.end = size;
return;
}
const data = self.cache.get(self.io, self.cur_offset, block.size, size);
const data = self.cache.get(self.io, self.cur_offset, block.size, @truncate(size)) catch return error.ReadFailed;
if (data.len != size) {
std.debug.print("Size of decompression at {} is {} and should be {}\n", .{ self.cur_offset, data.len, size });
return Io.Reader.Error.ReadFailed;
+1 -1
View File
@@ -87,7 +87,7 @@ pub fn get(self: *DecompCache, io: Io, offset: u64, compressed_size: u32, max_si
pub fn finished(self: *DecompCache, io: Io, offset: u64) void {
const cache = self.cache.getPtr(offset);
if (cache == null) {
std.debug.print("Finished using cache, but cache does not exist: {}\n", .{offset});
// std.debug.print("Finished using cache, but cache does not exist: {}\n", .{offset});
return;
}
+29 -67
View File
@@ -2,7 +2,6 @@ const std = @import("std");
const Io = std.Io;
const Atomic = std.atomic.Value;
const DataExtractor = @import("data/extractor.zig");
const DataReader = @import("data/reader.zig");
const DecompCache = @import("decomp_cache.zig");
const Directory = @import("directory.zig");
@@ -12,7 +11,7 @@ const Lookup = @import("lookup.zig");
const Superblock = @import("archive.zig").Superblock;
const XattrTable = @import("xattr.zig");
pub fn extract(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCache, super: Superblock, ext_loc: []const u8, options: ExtractionOptions) !void {
pub fn extractSingleThreaded(alloc: std.mem.Allocator, io: Io, inode: Inode, cache: *DecompCache, super: Superblock, ext_loc: []const u8, options: ExtractionOptions) !void {
const path = std.mem.trim(u8, ext_loc, "/");
var id_table: Lookup.Table(u16) = .init(alloc, cache, super.id_start, super.id_count);
@@ -72,7 +71,7 @@ fn extractDir(
options: ExtractionOptions,
path: []const u8,
inode: Inode,
) Error!DirReturn(false) {
) Error!DirReturn {
try Io.Dir.cwd().createDirPath(io, path);
const dir = inode.directory(alloc, io, cache, super.dir_start) catch |err| switch (err) {
@@ -81,7 +80,7 @@ fn extractDir(
};
defer dir.deinit(alloc);
const ret: DirReturn(false) = .{
const ret: DirReturn = .{
.hdr = inode.hdr,
.path = path,
@@ -122,18 +121,18 @@ fn extractFile(
frag_table: *Lookup.Table(Lookup.FragmentEntry),
path: []const u8,
inode: Inode,
) Error!FileReturn(false) {
) Error!FileReturn {
var atomic = try Io.Dir.cwd().createFileAtomic(io, path, .{});
defer atomic.deinit(io);
var ret: FileReturn(false) = .{
var ret: FileReturn = .{
.hdr = inode.hdr,
.path = path,
};
const data: DataExtractor = switch (inode.data) {
var data: DataReader = switch (inode.data) {
.file => |f| blk: {
var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks);
var data: DataReader = .init(io, cache, block_size, f.size, f.data_start, f.blocks);
if (f.frag_idx != 0xFFFFFFFF) {
const entry: Lookup.FragmentEntry = try frag_table.get(io, f.frag_idx);
if (entry.size.uncompressed) {
@@ -146,7 +145,7 @@ fn extractFile(
break :blk data;
},
.ext_file => |f| blk: {
var data: DataExtractor = .init(cache, block_size, f.size, f.data_start, f.blocks);
var data: DataReader = .init(io, cache, block_size, f.size, f.data_start, f.blocks);
if (f.frag_idx != 0xFFFFFFFF) {
const entry: Lookup.FragmentEntry = try frag_table.get(io, f.frag_idx);
if (entry.size.uncompressed) {
@@ -162,7 +161,12 @@ fn extractFile(
},
else => unreachable,
};
try data.asyncExtract(io, atomic.file);
defer data.deinit();
var wrt_buf: [1024]u8 = undefined;
var wrt = atomic.file.writer(io, &wrt_buf);
_ = try data.interface.streamRemaining(&wrt.interface);
try wrt.flush();
try atomic.link(io);
@@ -177,8 +181,8 @@ fn extractSymlink(io: Io, path: []const u8, inode: Inode) Error!void {
try Io.Dir.cwd().symLink(io, target, path, .{});
}
fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode) Error!FileReturn(false) {
var ret: FileReturn(false) = .{
fn extractNod(alloc: std.mem.Allocator, path: []const u8, inode: Inode) Error!FileReturn {
var ret: FileReturn = .{
.hdr = inode.hdr,
.path = path,
};
@@ -259,67 +263,25 @@ fn setMetadata(alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), x
}
const Error = error{ Canceled, MknodError, SetXattrError } || Directory.Error || Io.Dir.CreateFileAtomicError || Io.File.Atomic.LinkError ||
DataExtractor.Error || Io.Dir.SymLinkError || Io.Dir.CreateDirPathError;
Io.Dir.SymLinkError || Io.Dir.CreateDirPathError || Io.Reader.StreamError || Io.File.SetPermissionsError;
const ReturnUnion = union(enum) {
file: Error!FileReturn,
dir: Error!DirReturn(true),
void: Error!void,
const FileReturn = struct {
hdr: Inode.Header,
path: []const u8,
xattr_idx: ?u32 = null,
fn finish(self: FileReturn, alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
}
};
fn FileReturn(comptime async: bool) type {
return if (async)
struct {
hdr: Inode.Header,
path: []const u8,
parent: ?*Atomic(u32),
xattr_idx: ?u32 = null,
fn finish(self: FileReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
defer if (self.parent != null) {
_ = self.parent.?.fetchSub(1, .acquire);
};
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
}
}
else
struct {
const DirReturn = struct {
hdr: Inode.Header,
path: []const u8,
xattr_idx: ?u32 = null,
fn finish(self: FileReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
fn finish(self: DirReturn, alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
}
};
}
fn DirReturn(comptime async: bool) type {
return if (async)
struct {
hdr: Inode.Header,
path: []const u8,
parent: ?*Atomic(u32),
xattr_idx: ?u32 = null,
fn finish(self: DirReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
defer if (self.parent != null) {
_ = self.parent.?.fetchSub(1, .acquire);
};
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
}
}
else
struct {
hdr: Inode.Header,
path: []const u8,
xattr_idx: ?u32 = null,
fn finish(self: DirReturn(async), alloc: std.mem.Allocator, io: Io, id_table: *Lookup.Table(u16), xattr_table: *XattrTable, options: ExtractionOptions) Error!void {
return setMetadata(alloc, io, id_table, xattr_table, options, self.hdr, self.xattr_idx, self.path);
}
};
}
};
+1 -1
View File
@@ -103,5 +103,5 @@ pub fn open(self: *SfsFile, alloc: std.mem.Allocator, io: Io, filepath: []const
}
pub fn extract(self: *SfsFile, alloc: std.mem.Allocator, io: Io, ext_dir: []const u8, options: ExtractionOptions) !void {
return Extract.extract(alloc, io, self.inode, &self.archive.cache, self.archive.super, ext_dir, options);
return Extract.extractSingleThreaded(alloc, io, self.inode, &self.archive.cache, self.archive.super, ext_dir, options);
}