Uh oh!
There was an error while loading. Please reload this page.
different strategy for tokenizing keywords - #5442
Conversation
throughput: 279 MiB/s => 347 MiB/s
Vexu
left a comment
There was a problem hiding this comment.
This should be faster but could you also run the throughput test for the hashmap version?
andrewrk
commented
May 26, 2020
benchmark code: conststd=@import("std");
pubfnsetup(gpa: *std.mem.Allocator, options: *Options) !void {}
varglobal_total_byte_count: u64=undefined;
varglobal_total_token_count: u64=undefined;
pubfnrun(gpa: *std.mem.Allocator, context: void) !void {
varwalker=trystd.fs.walkPath(gpa, "../lib/std");
deferwalker.deinit();
vartotal_byte_count: u64=0;
vartotal_token_count: u64=0;
while (trywalker.next()) |entry|switch (entry.kind) {
.File=> {
if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue;
constsource=tryentry.dir.readFileAlloc(gpa, entry.basename, 30*1024*1024);
defergpa.free(source);
total_byte_count+=source.len;
vartokenizer=std.zig.Tokenizer.init(source);
while (true) {
consttoken=tokenizer.next();
total_token_count+=1;
if (token.id==.Eof) break;
}
},
else=>continue,
};
global_total_byte_count=total_byte_count;
global_total_token_count=total_token_count;
}
pubconstMeasurement=struct {
median: u64,
mean: u64,
min: u64,
max: u64,
fncompute(all_samples: []Sample, comptimefield: []constu8) Measurement {
constS=struct {
fnorder(a: Sample, b: Sample) bool {
return@field(a, field) <@field(b, field);
}
};
// Remove the 2 outliersstd.sort.sort(Sample, all_samples, S.order);
constsamples=all_samples[1..all_samples.len-1];
// Compute statsvartotal: u64=0;
varmin: u64=std.math.maxInt(u64);
varmax: u64=0;
for (samples) |s| {
constv=@field(s, field);
total+=v;
if (v<min) min=v;
if (v>max) max=v;
}
return .{
.median=@field(samples[samples.len/2], field),
.mean=total/samples.len,
.min=min,
.max=max,
};
}
};
pubconstResults=union(enum) {
fail: anyerror,
ok: struct {
samples_taken: usize,
wall_time: Measurement,
utime: Measurement,
stime: Measurement,
maxrss: usize,
},
};
constSample=struct {
wall_time: u64,
utime: u64,
stime: u64,
};
fntimeval_to_ns(timeval: std.os.timeval) u64 {
constns_per_us=std.time.ns_per_s/std.time.us_per_s;
return@bitCast(usize, timeval.tv_sec) *std.time.ns_per_s+@bitCast(usize, timeval.tv_usec) *ns_per_us;
}
varsamples_buf: [1000000]Sample=undefined;
constmax_nano_seconds=std.time.ns_per_s*20;
pubfnbench(options: Options, comptimefunc: var, args: var) Results {
varsample_index: usize=0;
consttimer=std.time.Timer.start() catch@panic("need timer to work");
constfirst_start=timer.read();
while ((sample_index<3or
(timer.read() -first_start) <max_nano_seconds) andsample_index<samples_buf.len)
{
conststart_rusage=std.os.getrusage(options.rusage_who);
conststart=timer.read();
@call(.{}, func, args) catch|err| {
return .{ .fail=err };
};
constend=timer.read();
constend_rusage=std.os.getrusage(options.rusage_who);
samples_buf[sample_index] = .{
.wall_time=end-start,
.utime=timeval_to_ns(end_rusage.utime) -timeval_to_ns(start_rusage.utime),
.stime=timeval_to_ns(end_rusage.stime) -timeval_to_ns(start_rusage.stime),
};
sample_index+=1;
}
constall_samples=samples_buf[0..sample_index];
constwall_time=Measurement.compute(all_samples, "wall_time");
constutime=Measurement.compute(all_samples, "utime");
conststime=Measurement.compute(all_samples, "stime");
constfinal_rusage=std.os.getrusage(options.rusage_who);
std.debug.warn("total_token_count={}\ntotal_byte_count={}\n", .{global_total_token_count, global_total_byte_count});
{
constelapsed_s=@intToFloat(f64, wall_time.mean) /std.time.ns_per_s;
constthroughput=@floatToInt(u64, @intToFloat(f64, global_total_byte_count) /elapsed_s);
std.debug.warn("throughput (mean): {Bi}/s\n", .{throughput});
}
{
constelapsed_s=@intToFloat(f64, wall_time.median) /std.time.ns_per_s;
constthroughput=@floatToInt(u64, @intToFloat(f64, global_total_byte_count) /elapsed_s);
std.debug.warn("throughput (median): {Bi}/s\n", .{throughput});
}
{
constelapsed_s=@intToFloat(f64, wall_time.max) /std.time.ns_per_s;
constthroughput=@floatToInt(u64, @intToFloat(f64, global_total_byte_count) /elapsed_s);
std.debug.warn("throughput (min): {Bi}/s\n", .{throughput});
}
{
constelapsed_s=@intToFloat(f64, wall_time.min) /std.time.ns_per_s;
constthroughput=@floatToInt(u64, @intToFloat(f64, global_total_byte_count) /elapsed_s);
std.debug.warn("throughput (max): {Bi}/s\n", .{throughput});
}
return .{
.ok= .{
.samples_taken=all_samples.len,
.wall_time=wall_time,
.utime=utime,
.stime=stime,
.maxrss=@bitCast(usize, final_rusage.maxrss),
},
};
}
pubconstOptions=struct {
rusage_who: i32=std.os.RUSAGE_SELF,
};
pubfnmain() !void {
constgpa=if (std.builtin.link_libc) std.heap.c_allocatorelsestd.heap.page_allocator;
varoptions: Options= .{};
constcontext=trysetup(gpa, &options);
constresults=bench(options, run, .{ gpa, context });
trystd.json.stringify(results, std.json.StringifyOptions{}, std.io.getStdOut().outStream());
}run instructions: master: comptime hashmap: this branch: |
andrewrk
commented
May 26, 2020
I think it might be useful to start collecting instruction counts rather than wall clock timings because the wall clock timings tend to be highly variable for me |
andrewrk
commented
May 26, 2020
benchmark code: conststd=@import("std");
pubfnsetup(gpa: *std.mem.Allocator, options: *Options) !void {}
varglobal_total_byte_count: u64=undefined;
varglobal_total_token_count: u64=undefined;
pubfnrun(gpa: *std.mem.Allocator, context: void) !void {
varwalker=trystd.fs.walkPath(gpa, "../lib/std");
deferwalker.deinit();
vartotal_byte_count: u64=0;
vartotal_token_count: u64=0;
while (trywalker.next()) |entry|switch (entry.kind) {
.File=> {
if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue;
constsource=tryentry.dir.readFileAlloc(gpa, entry.basename, 30*1024*1024);
defergpa.free(source);
total_byte_count+=source.len;
vartokenizer=std.zig.Tokenizer.init(source);
while (true) {
consttoken=tokenizer.next();
total_token_count+=1;
if (token.id==.Eof) break;
}
},
else=>continue,
};
global_total_byte_count=total_byte_count;
global_total_token_count=total_token_count;
}
pubconstOptions=struct {
rusage_who: i32=std.os.RUSAGE_SELF,
};
pubfnmain() !void {
constgpa=if (std.builtin.link_libc) std.heap.c_allocatorelsestd.heap.page_allocator;
varoptions: Options= .{};
constcontext=trysetup(gpa, &options);
tryrun(gpa, context);
}run instructions: master: comptime hash map: this branch: |
data-man
commented
May 26, 2020
BTW, I thought about the built-in benchmarking, and then I found #1010. |
squeek502
commented
May 26, 2020
An attempt at making this lookup implementation reusable: https://gist.github.com/squeek502/7f7db10c520bacff4c24b22c9102db8d |
andrewrk
commented
May 26, 2020
@squeek502 oh of course, this could be a generic improvement to Want to make that a follow-up PR? |
Add std.ComptimeStringMap based on the tokenizer optimization in #5442
I did my idea from #5359 (comment)
throughput: 279 MiB/s => 347 MiB/s