Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General updates for Zig v0.11.0-dev #17

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "benchmark/libs/zig-yaml"]
path = benchmark/libs/zig-yaml
url = https://github.com/kubkon/zig-yaml
16 changes: 8 additions & 8 deletions benchmark/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,26 @@
)

# Parsing with zaml: Prototype YAML parser written in Zig:
start = time.time()
start = time.perf_counter()
zaml_result = zaml.load(big_yaml)
print(f"Benchmark results:\nzaml took {(time.time() - start):.2f} seconds")
print(f"Benchmark results:\nzaml took {(time.perf_counter() - start):.4f} seconds")

# Parsing with PyYAML in C:
start = time.time()
start = time.perf_counter()
pyyaml_c_result = pyyaml.load(big_yaml, Loader=pyyaml.CSafeLoader)
print(f"PyYAML CSafeLoader took {(time.time() - start):.2f} seconds")
print(f"PyYAML CSafeLoader took {(time.perf_counter() - start):.4f} seconds")

# Parsing with ruamel:
start = time.time()
start = time.perf_counter()
yaml = YAML(typ="safe")
yaml.load(big_yaml)
rueaml_result = yaml.load(big_yaml)
print(f"ruamel took {(time.time() - start):.2f} seconds")
print(f"ruamel took {(time.perf_counter() - start):.4f} seconds")

# Parsing with PyYAML:
start = time.time()
start = time.perf_counter()
pyyaml_result = pyyaml.load(big_yaml, Loader=pyyaml.SafeLoader)
print(f"PyYAML SafeLoader took {(time.time() - start):.2f} seconds")
print(f"PyYAML SafeLoader took {(time.perf_counter() - start):.4f} seconds")


assert zaml_result == pyyaml_result == pyyaml_c_result == rueaml_result
50 changes: 28 additions & 22 deletions benchmark/benchmark.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ const std = @import("std");

// Zig library for parsing yaml
// https://github.com/kubkon/zig-yaml
// TODO: include this as a Git submodule or as a package (when Zig gets official package manager)
const yaml = @import("libs/zig-yaml/src/main.zig");
const yaml = @import("libs/zig-yaml/src/yaml.zig");

const PyArg_ParseTuple = py.PyArg_ParseTuple;
const PyObject = py.PyObject;
Expand All @@ -21,42 +20,50 @@ const PyDict_SetItem = py.PyDict_SetItem;
const Py_BuildValue = py.Py_BuildValue;
const METH_VARARGS = py.METH_VARARGS;

// Would not use "testing" allocator for production
const test_allocator = std.testing.allocator;
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};

// Don't think about using this in production, it probably has bugs + memory leaks
fn benchmark_load(self: [*c]PyObject, args: [*c]PyObject) callconv(.C) [*]PyObject {
fn benchmark_load(self: [*c]PyObject, args: [*c]PyObject) callconv(.C) [*c]PyObject {
_ = self;

var string: [*:0]const u8 = undefined;
// TODO: handle errors / unexpected input. Probably not a good idea to silently ignore them.
_ = PyArg_ParseTuple(args, "s", &string);
if (PyArg_ParseTuple(args, "s", &string) == 0) return null;

// "catch unreachable" tells Zig compiler this can't possibly fail
// Of course, it might fail: this is just a benchmark.
// Did I mention not to use this in production?
var untyped = yaml.Yaml.load(std.testing.allocator, std.mem.sliceTo(string, 0)) catch unreachable;
// Free all memory at the end of the current scope
defer untyped.deinit();
var arena = std.heap.ArenaAllocator.init(general_purpose_allocator.allocator());
defer arena.deinit();
const allocator = arena.allocator();

// TODO: remove 'catch unreachable' by catching the YamlError
// https://github.com/kubkon/zig-yaml/blob/3d3c7ae400243a37c6b422b6cba7173656984897/src/yaml.zig#L17-L22
// define and set an appropriate error
// https://docs.python.org/3.9/extending/extending.html#intermezzo-errors-and-exceptions
// and return null as above
var untyped = yaml.Yaml.load(allocator, std.mem.sliceTo(string, 0)) catch unreachable;

// TODO: same as TODO on ln 50 but maybe assert on `docs` size
// Our friend "catch unreachable" again :)
var map = untyped.docs.items[0].asMap() catch unreachable;

var dict = PyDict_New();

const keys = map.keys();
for (map.keys(), map.values()) |key, value| {
// TODO: `value` type can be any of https://github.com/kubkon/zig-yaml/blob/3d3c7ae400243a37c6b422b6cba7173656984897/src/yaml.zig#L28-L33
// Suggestion to handle the type appropriately
// 1. Pattern match on value type
// 2. Build the corresponsing PyObject https://docs.python.org/3.9/extending/extending.html#building-arbitrary-values
// 3. Return its pointer

for (keys) |key| {
const value = map.get(key) orelse unreachable;
var pyKey = Py_BuildValue("s#", @ptrCast([*]const u8, key), key.len);
var valueStr = value.asString() catch unreachable;
const pyValue = Py_BuildValue("s#", @ptrCast([*]const u8, valueStr), valueStr.len);
var value_str = value.asString() catch unreachable;

// TODO: again, we just ignore the potential errors that could happen here.
// Don't do that in real life!
_ = PyDict_SetItem(dict, pyKey, pyValue);
}
const py_key_ptr: [*]const u8 = @ptrCast(key);
const py_value_ptr: [*]const u8 = @ptrCast(value_str);

const py_key = Py_BuildValue("s#", py_key_ptr, key.len);
const py_value = Py_BuildValue("s#", py_value_ptr, value_str.len);
_ = PyDict_SetItem(dict, py_key, py_value);
}

return Py_BuildValue("O", dict);
}
Expand Down Expand Up @@ -99,4 +106,3 @@ var benchmarkmodule = PyModuleDef{
pub export fn PyInit_benchmark() [*]PyObject {
return PyModule_Create(&benchmarkmodule);
}

1 change: 1 addition & 0 deletions benchmark/libs/zig-yaml
Submodule zig-yaml added at 3d3c7a
22 changes: 0 additions & 22 deletions benchmark/libs/zig-yaml/LICENSE

This file was deleted.

90 changes: 0 additions & 90 deletions benchmark/libs/zig-yaml/README.md

This file was deleted.

35 changes: 0 additions & 35 deletions benchmark/libs/zig-yaml/build.zig

This file was deleted.

12 changes: 0 additions & 12 deletions benchmark/libs/zig-yaml/ci/linux_ci

This file was deleted.

12 changes: 0 additions & 12 deletions benchmark/libs/zig-yaml/ci/macos_ci

This file was deleted.

12 changes: 0 additions & 12 deletions benchmark/libs/zig-yaml/ci/win_ci

This file was deleted.

4 changes: 0 additions & 4 deletions benchmark/libs/zig-yaml/examples/explicit_doc.yml

This file was deleted.

7 changes: 0 additions & 7 deletions benchmark/libs/zig-yaml/examples/lists.yml

This file was deleted.

9 changes: 0 additions & 9 deletions benchmark/libs/zig-yaml/examples/map_of_lists.yml

This file was deleted.

8 changes: 0 additions & 8 deletions benchmark/libs/zig-yaml/examples/maps.yml

This file was deleted.

2 changes: 0 additions & 2 deletions benchmark/libs/zig-yaml/examples/simple.yml

This file was deleted.

41 changes: 0 additions & 41 deletions benchmark/libs/zig-yaml/examples/yaml.zig

This file was deleted.

Loading