From 70b6dfbd08a8e38145b8b1a31a01d8b7b74ac1b1 Mon Sep 17 00:00:00 2001 From: RDW Date: Thu, 16 Jan 2025 03:46:34 +0100 Subject: [PATCH] Perf: Add a benchmark for the iconv FFI bindings Certainly not the most representative workload, but it'll do. --- Benchmarks/iconv-charset-conversion.lua | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Benchmarks/iconv-charset-conversion.lua diff --git a/Benchmarks/iconv-charset-conversion.lua b/Benchmarks/iconv-charset-conversion.lua new file mode 100644 index 000000000..9b9c98426 --- /dev/null +++ b/Benchmarks/iconv-charset-conversion.lua @@ -0,0 +1,74 @@ +local console = require("console") +local iconv = require("iconv") +local ffi = require("ffi") + +local SAMPLE_SIZE = 500000 + +local function iconv_lowlevel() + local input = "\192\175\192\250\192\206\197\205\198\228\192\204\189\186" + local descriptor = iconv.bindings.iconv_open("UTF-8", "CP949") + + local inputSize = ffi.new("size_t[1]", #input) + local inputBuffer = ffi.new("char[?]", #input, input) + local inputRef = ffi.new("char*[1]", inputBuffer) + + local worstCaseOutputSize = #input * 4 + local outputSize = ffi.new("size_t[1]", worstCaseOutputSize) + local outputBuffer = ffi.new("char[256]") + local outputRef = ffi.new("char*[1]", outputBuffer) + + local result = iconv.bindings.iconv(descriptor, inputRef, inputSize, outputRef, outputSize) + local numConversionsPerformed = worstCaseOutputSize - outputSize[0] + local converted = ffi.string(outputBuffer, numConversionsPerformed) + + iconv.bindings.iconv_close(descriptor) + return converted, result +end + +local function iconv_lua() + local input = "\192\175\192\250\192\206\197\205\198\228\192\204\189\186" + local output, message = iconv.convert(input, "CP949", "UTF-8") + return output, message +end + +local function iconv_cpp() + local inputBuffer = buffer.new() + local outputBuffer = buffer.new(1024) + local ptr, len = outputBuffer:reserve(1024) + local result = iconv.bindings.iconv_convert(inputBuffer, #inputBuffer, "CP949", "UTF-8", ptr, len) + return result +end + +math.randomseed(os.clock()) +local availableBenchmarks = { + function() + local label = "[FFI] Low-level API (tedious and slow, but the most flexible)" + console.startTimer(label) + for i = 1, SAMPLE_SIZE, 1 do + iconv_lowlevel() + end + console.stopTimer(label) + end, + function() + local label = "[FFI] One-shot C++ conversion (fast but less flexible)" + console.startTimer(label) + for i = 1, SAMPLE_SIZE, 1 do + iconv_cpp() + end + console.stopTimer(label) + end, + function() + local label = "[FFI] Lua-friendly wrapper (safer, but slower)" + console.startTimer(label) + for i = 1, SAMPLE_SIZE, 1 do + iconv_lua() + end + console.stopTimer(label) + end, +} + +table.shuffle(availableBenchmarks) + +for _, benchmark in ipairs(availableBenchmarks) do + benchmark() +end