Skip to content

Commit 88690dd

Browse files
committed
test: add backing store tests
1 parent df64dbd commit 88690dd

12 files changed

Lines changed: 641 additions & 21 deletions

src/cartesi-machine.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2068,7 +2068,7 @@ echo "
20682068
end
20692069

20702070
for _, r in ipairs(memory_range_replace) do
2071-
main_machine:replace_memory_range(r.start, r.length, r.shared, r.image_filename)
2071+
main_machine:replace_memory_range(r)
20722072
end
20732073

20742074
local function dump_config(what, whatdef, out, indent)

src/machine-address-ranges.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ static void prepare_ar_backing_store_for_share(const backing_store_config &from_
218218
os::truncate_file(to_c.dpt_filename, dpt_length, true);
219219
}
220220
remover.add_file(to_c.dpt_filename);
221+
222+
os::change_writable(to_c.data_filename, !read_only);
221223
}
222-
os::change_writable(to_c.data_filename, !read_only);
223224
}
224225

225226
static void prepare_ar_backing_stores(const machine_config &c, scope_remove &remover) {

src/machine-config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ std::string machine_config::get_dpt_filename(const std::string &dir, uint64_t st
5555
}
5656

5757
std::string machine_config::get_sht_filename(const std::string &dir) {
58-
return dir + "/global.sht";
58+
return dir + "/hash_tree.sht";
5959
}
6060

6161
std::string machine_config::get_phtc_filename(const std::string &dir) {
62-
return dir + "/global.phtc";
62+
return dir + "/hash_tree.phtc";
6363
}
6464

6565
std::string machine_config::get_config_filename(const std::string &dir) {

src/machine-config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ struct machine_config final {
210210
machine_config &adjust_defaults();
211211

212212
/// \brief Adjust backing stores to point to the directory
213+
/// \param dir Directory where "config" is stored
214+
/// \param sharing Sharing mode conversion policy to use for backing stores
213215
machine_config &adjust_backing_stores(const std::string &dir, sharing_mode sharing = sharing_mode::config);
214216

215217
/// \brief Loads a machine config from a directory

src/machine.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ void machine::store(const std::string &dir, sharing_mode sharing) const {
395395
remover.add_directory(dir);
396396

397397
// Store config
398-
remover.add_file(m_c.store(dir, sharing));
398+
remover.add_file(m_c.store(dir));
399399

400400
// Store all address ranges
401401
auto store_address_range = [&](const backing_store_config &c, const address_range &ar, bool read_only) {
@@ -418,10 +418,10 @@ void machine::store(const std::string &dir, sharing_mode sharing) const {
418418
remover.add_file(dpt_filename);
419419
} else { // Copy unshared backing store
420420
if (c.data_filename.empty()) {
421-
throw std::runtime_error{"attempt to restore unbacked address range "s.append(ar.get_description())};
421+
throw std::runtime_error{"attempt to rollback unbacked address range "s.append(ar.get_description())};
422422
}
423423
if (c.shared) {
424-
throw std::runtime_error{"attempt to restore shared address range "s.append(ar.get_description())};
424+
throw std::runtime_error{"attempt to rollback shared address range "s.append(ar.get_description())};
425425
}
426426
os::copy_file(c.data_filename, data_filename, ar.get_length());
427427
remover.add_file(data_filename);
@@ -462,8 +462,8 @@ void machine::store(const std::string &dir, sharing_mode sharing) const {
462462
} else {
463463
os::truncate_file(sht_filename, m_ht.get_sht_storage_data().size(), true);
464464
remover.add_file(sht_filename);
465-
os::truncate_file(sht_filename, m_ht.get_phtc_storage_data().size(), true);
466-
remover.add_file(sht_filename);
465+
os::truncate_file(phtc_filename, m_ht.get_phtc_storage_data().size(), true);
466+
remover.add_file(phtc_filename);
467467
}
468468

469469
// Retain all stored files

src/os-mapped-memory.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ mapped_memory::mapped_memory(uint64_t length, const mapped_memory_flags &flags,
144144

145145
// Check backing file length mismatch
146146
if (backing_file_length != desired_backing_length) {
147+
if (backing_file_length > desired_backing_length) {
148+
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
149+
std::to_string(backing_file_length) + ") cannot be less than desired backing length ("s +
150+
std::to_string(desired_backing_length) + ")"s};
151+
}
147152
if (flags.shared || !flags.backing_gap) {
148153
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
149154
std::to_string(backing_file_length) + ") does not match desired backing length ("s +
@@ -214,7 +219,7 @@ mapped_memory::mapped_memory(uint64_t length, const mapped_memory_flags &flags,
214219
if (flags.read_only) {
215220
// We can't write on read-only mappings.
216221
// This kind of mapping is unlikely to happen, so there is no need to support it.
217-
throw std::system_error{errno, std::generic_category(),
222+
throw std::runtime_error{
218223
"possible non zero partial page when mapping backing file '"s + backing_filename + "' to memory"s};
219224
}
220225
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -304,6 +309,11 @@ mapped_memory::mapped_memory(uint64_t length, const mapped_memory_flags &flags,
304309

305310
// Check backing file length mismatch
306311
if (backing_file_length != desired_backing_length) {
312+
if (backing_file_length > desired_backing_length) {
313+
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
314+
std::to_string(backing_file_length) + ") cannot be less than desired backing length ("s +
315+
std::to_string(desired_backing_length) + ")"s};
316+
}
307317
if (flags.shared || !flags.backing_gap) {
308318
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
309319
std::to_string(backing_file_length) + ") does not match desired backing length ("s +
@@ -455,6 +465,11 @@ mapped_memory::mapped_memory(uint64_t length, const mapped_memory_flags &flags,
455465

456466
// Check backing file length mismatch
457467
if (backing_file_length != desired_backing_length) {
468+
if (backing_file_length > desired_backing_length) {
469+
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
470+
std::to_string(backing_file_length) + ") cannot be less than desired backing length ("s +
471+
std::to_string(desired_backing_length) + ")"s};
472+
}
458473
if (flags.shared || !flags.backing_gap) {
459474
throw std::runtime_error{"backing file '"s + backing_filename + "' length ("s +
460475
std::to_string(backing_file_length) + ") does not match desired backing length ("s +

tests/lua/cartesi/filesystem.lua

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
-- Copyright Cartesi and individual authors (see AUTHORS)
2+
-- SPDX-License-Identifier: LGPL-3.0-or-later
3+
--
4+
-- This program is free software: you can redistribute it and/or modify it under
5+
-- the terms of the GNU Lesser General Public License as published by the Free
6+
-- Software Foundation, either version 3 of the License, or (at your option) any
7+
-- later version.
8+
--
9+
-- This program is distributed in the hope that it will be useful, but WITHOUT ANY
10+
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11+
-- PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12+
--
13+
-- You should have received a copy of the GNU Lesser General Public License along
14+
-- with this program (see COPYING). If not, see <https://www.gnu.org/licenses/>.
15+
--
16+
17+
local utils = require("cartesi.utils")
18+
19+
-- Module providing helpers for filesystem operations.
20+
local filesystem = {}
21+
22+
-- Creates a temporary filename (an empty file is also created).
23+
function filesystem.temp_filename()
24+
return (assert(os.tmpname()))
25+
end
26+
27+
-- Returns a temporary path name (without creating a file or directory).
28+
function filesystem.temp_pathname()
29+
local pathname = assert(os.tmpname())
30+
assert(os.remove(pathname))
31+
return pathname
32+
end
33+
34+
-- Reads binary data from a file.
35+
function filesystem.read_file(filename)
36+
local f <close> = assert(io.open(filename, "rb"))
37+
return (assert(f:read("a")))
38+
end
39+
40+
-- Writes a binary data to a new file (the file is overwritten if it exists).
41+
function filesystem.write_file(filename, data)
42+
local f <close> = assert(io.open(filename, "wb"))
43+
assert(f:write(data))
44+
end
45+
46+
-- Returns the size of a file in bytes.
47+
function filesystem.get_file_size(filename)
48+
local f <close> = assert(io.open(filename, "rb"))
49+
return (assert(f:seek("end")))
50+
end
51+
52+
-- Writes a binary data to a temporary file.
53+
function filesystem.write_temp_file(data)
54+
local filename = filesystem.temp_filename()
55+
local ok, err = pcall(function()
56+
filesystem.write_file(filename, data)
57+
end)
58+
if not ok then
59+
os.remove(filename)
60+
end
61+
assert(ok, err)
62+
return filename
63+
end
64+
65+
-- Writes a binary data to a temporary file that is auto removed when scoped ends.
66+
function filesystem.write_scope_temp_file(data)
67+
local filename = filesystem.write_temp_file(data)
68+
return utils.scope_exit(function()
69+
filesystem.remove_file(filename)
70+
end), filename
71+
end
72+
73+
-- Removes a file.
74+
function filesystem.remove_file(filename)
75+
assert(os.remove(filename))
76+
end
77+
78+
return filesystem

tests/lua/cartesi/tabular.lua

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,79 @@
1414
-- with this program (see COPYING). If not, see <https://www.gnu.org/licenses/>.
1515
--
1616

17-
-- module to convert array tables into key-value tables
18-
local M = {}
17+
-- Module with helpers for table manipulations.
18+
local tabular = {}
1919

20-
-- convert a table with indexed rows into a table with named rows. e.g.
20+
-- Convert a table with indexed rows into a table with named rows. e.g.
2121
-- {"foo", 999} -> {name = "foo", cycles = 999} with keys described by md
22-
local function expand_row(metadata, row)
22+
function tabular.expand_row(metadata, row)
2323
local expanded_row = {}
2424
for key, val in ipairs(metadata) do
2525
expanded_row[val] = row[key]
2626
end
2727
return expanded_row
2828
end
2929

30-
-- apply `expand_row` for each row of `t`. e.g.
30+
-- Apply `expand_row` for each row of `t`. e.g.
3131
-- {{ "foo", 999 }} -> {{name = "foo", cycles = 999}} with keys described by md
32-
M.expand = function(metadata, t)
32+
function tabular.expand(metadata, t)
3333
local expanded_t = {}
3434
for _, row in ipairs(t) do
35-
expanded_t[#expanded_t + 1] = expand_row(metadata, row)
35+
expanded_t[#expanded_t + 1] = tabular.expand_row(metadata, row)
3636
end
3737
return expanded_t
3838
end
3939

40-
function M.clear(t)
40+
-- Clear all key-value pairs from table `t`.
41+
function tabular.clear(t)
4142
for k in pairs(t) do
4243
t[k] = nil
4344
end
4445
end
4546

46-
function M.append(t, elems)
47+
-- Append all elements from `elems` to the end of table `t`.
48+
function tabular.append(t, elems)
4749
local n = #t
4850
for i = 1, #elems do
4951
t[n + i] = elems[i]
5052
end
5153
end
5254

53-
return M
55+
local function deep_traverse_iter(t, path)
56+
path = path or {}
57+
for k, v in pairs(t) do
58+
local current_path = {}
59+
for i = 1, #path do
60+
current_path[i] = path[i]
61+
end
62+
current_path[#current_path + 1] = k
63+
if type(v) == "table" then
64+
deep_traverse_iter(v, current_path)
65+
else
66+
coroutine.yield(current_path, k, v)
67+
end
68+
end
69+
end
70+
71+
-- Iterator that recursively traverses all key-value pairs in table `t`,
72+
-- yielding the path to each value, its key, and the value itself.
73+
function tabular.deep_traverse(t)
74+
return coroutine.wrap(function()
75+
deep_traverse_iter(t)
76+
end)
77+
end
78+
79+
-- Recursively copy a table `t` and all its subtables.
80+
function tabular.deep_copy(t)
81+
local copy = {}
82+
for k, v in pairs(t) do
83+
if type(v) == "table" then
84+
copy[k] = tabular.deep_copy(v)
85+
else
86+
copy[k] = v
87+
end
88+
end
89+
return copy
90+
end
91+
92+
return tabular

tests/lua/cartesi/utils.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-- Copyright Cartesi and individual authors (see AUTHORS)
2+
-- SPDX-License-Identifier: LGPL-3.0-or-later
3+
--
4+
-- This program is free software: you can redistribute it and/or modify it under
5+
-- the terms of the GNU Lesser General Public License as published by the Free
6+
-- Software Foundation, either version 3 of the License, or (at your option) any
7+
-- later version.
8+
--
9+
-- This program is distributed in the hope that it will be useful, but WITHOUT ANY
10+
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11+
-- PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12+
--
13+
-- You should have received a copy of the GNU Lesser General Public License along
14+
-- with this program (see COPYING). If not, see <https://www.gnu.org/licenses/>.
15+
--
16+
17+
-- Module providing utilities.
18+
local utils = {}
19+
20+
-- Executes a callback when the scope exits.
21+
-- REMARKS: Use <close> on its returned value to make it behave deterministically.
22+
function utils.scope_exit(callback)
23+
return setmetatable({}, { __gc = callback, __close = callback })
24+
end
25+
26+
return utils

tests/lua/mcycle-overflow.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ local MAX_UARCH_CYCLE = cartesi.UARCH_CYCLE_MAX
2525
local function build_machine()
2626
local config = {
2727
ram = {
28-
image_filename = test_util.tests_path .. "mcycle_overflow.bin",
2928
length = 32 << 20,
29+
backing_store = {
30+
data_filename = test_util.tests_path .. "mcycle_overflow.bin",
31+
},
3032
},
3133
}
3234
local machine = cartesi.machine(config)

0 commit comments

Comments
 (0)