-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlookup.zig
More file actions
91 lines (79 loc) · 3.5 KB
/
lookup.zig
File metadata and controls
91 lines (79 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// The benchmark is contributed by @oschwald.
const std = @import("std");
const maxminddb = @import("maxminddb");
const default_db_path: []const u8 = "GeoLite2-City.mmdb";
const default_num_lookups: u64 = 1_000_000;
const max_mmdb_fields = 32;
pub fn main(init: std.process.Init) !void {
const allocator = init.gpa;
const io = init.io;
var args = try std.process.Args.Iterator.initAllocator(init.minimal.args, allocator);
defer args.deinit();
_ = args.skip();
const db_path = args.next() orelse default_db_path;
var num_lookups = default_num_lookups;
var fields: ?[]const []const u8 = null;
var index_bits: u8 = 16;
if (args.next()) |arg| num_lookups = try std.fmt.parseUnsigned(u64, arg, 10);
if (args.next()) |arg| {
const f = try maxminddb.Fields(max_mmdb_fields).parse(arg, ',');
fields = f.only();
}
if (args.next()) |arg| index_bits = try std.fmt.parseUnsigned(u8, arg, 10);
std.debug.print("Benchmarking with:\n", .{});
std.debug.print(" Database: {s}\n", .{db_path});
std.debug.print(" Lookups: {d}\n", .{num_lookups});
std.debug.print("Opening database...\n", .{});
const open_start = std.Io.Clock.Timestamp.now(io, .awake);
var db = try maxminddb.Reader.mmap(allocator, io, db_path, .{ .ipv4_index_first_n_bits = index_bits });
defer db.close();
const open_elapsed_ns: i64 = @intCast(open_start.untilNow(io).raw.nanoseconds);
const open_time_ms = @as(f64, @floatFromInt(open_elapsed_ns)) /
@as(f64, @floatFromInt(std.time.ns_per_ms));
std.debug.print("Database opened successfully in {d} ms. Type: {s}\n", .{
open_time_ms,
db.metadata.database_type,
});
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
std.debug.print("Starting benchmark...\n", .{});
const timer_start = std.Io.Clock.Timestamp.now(io, .awake);
var not_found_count: u64 = 0;
var lookup_errors: u64 = 0;
var ip_bytes: [4]u8 = undefined;
for (0..num_lookups) |_| {
io.random(&ip_bytes);
const ip: std.Io.net.IpAddress = .{ .ip4 = .{ .bytes = ip_bytes, .port = 0 } };
const result = db.lookup(
maxminddb.geolite2.City,
arena_allocator,
ip,
.{ .only = fields },
) catch |err| {
std.debug.print("! Lookup error for IP {any}: {any}\n", .{ ip, err });
lookup_errors += 1;
continue;
};
if (result == null) {
not_found_count += 1;
continue;
}
_ = arena.reset(.retain_capacity);
}
const elapsed_ns: i64 = @intCast(timer_start.untilNow(io).raw.nanoseconds);
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) /
@as(f64, @floatFromInt(std.time.ns_per_s));
const lookups_per_second = if (elapsed_s > 0)
@as(f64, @floatFromInt(num_lookups)) / elapsed_s
else
0.0;
const successful_lookups = num_lookups - not_found_count - lookup_errors;
std.debug.print("\n--- Benchmark Finished ---\n", .{});
std.debug.print("Total Lookups Attempted: {d}\n", .{num_lookups});
std.debug.print("Successful Lookups: {d}\n", .{successful_lookups});
std.debug.print("IPs Not Found: {d}\n", .{not_found_count});
std.debug.print("Lookup Errors: {d}\n", .{lookup_errors});
std.debug.print("Elapsed Time: {d} s\n", .{elapsed_s});
std.debug.print("Lookups Per Second (avg):{d}\n", .{lookups_per_second});
}