Skip to content

Commit ad7d1c5

Browse files
committed
Add remote JSON test with verification
1 parent 3a1b12b commit ad7d1c5

File tree

7 files changed

+214
-12
lines changed

7 files changed

+214
-12
lines changed

guest/storage/CMakeLists.txt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(storage)
3+
4+
set(CMAKE_CXX_STANDARD 20)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
7+
option(BUILD_SHARED_LIBS "" OFF)
8+
option(BUILD_TESTING "" OFF)
9+
option(RAPIDJSON_BUILD_DOC "" OFF)
10+
option(RAPIDJSON_BUILD_EXAMPLES "" OFF)
11+
option(RAPIDJSON_BUILD_TESTS "" OFF)
12+
option(RAPIDJSON_BUILD_CXX20 "" ON)
13+
include(FetchContent)
14+
FetchContent_Declare(rapidjson
15+
GIT_REPOSITORY https://github.com/Tencent/rapidjson.git
16+
GIT_TAG master
17+
)
18+
FetchContent_MakeAvailable(rapidjson)
19+
20+
# Build storage first
21+
add_executable(storage
22+
storage.cpp
23+
)
24+
target_compile_options(storage PRIVATE -Wall -Wextra -Wpedantic)
25+
target_link_libraries(storage PRIVATE -static -Wl,-Ttext-segment=0x44000000)
26+
target_link_libraries(storage PRIVATE RapidJSON)
27+
target_include_directories(storage PUBLIC
28+
${CMAKE_CURRENT_SOURCE_DIR}
29+
${CMAKE_BINARY_DIR}/_deps/rapidjson-src/include
30+
)
31+
32+
# Now execute objcopy to extract symbols
33+
# objcopy -w --extract-symbol --strip-symbol=!remote* --strip-symbol=!_Z*remote* --strip-symbol=* storage storage.syms
34+
# Output: storage.syms
35+
add_custom_command(
36+
COMMAND objcopy -w --extract-symbol --strip-symbol=!remote* --strip-symbol=!_Z*remote* --strip-symbol=* storage storage.syms
37+
OUTPUT storage.syms
38+
DEPENDS storage
39+
)
40+
add_custom_target(extract_symbols
41+
DEPENDS storage.syms
42+
)
43+
44+
# Now build main, linking against the symbols from storage.syms
45+
add_executable(main
46+
main.cpp
47+
)
48+
target_compile_options(main PRIVATE -Wall -Wextra -Wpedantic)
49+
target_link_libraries(main PRIVATE -static -Wl,--just-symbols=$<TARGET_FILE:storage>.syms)
50+
target_link_libraries(main PRIVATE RapidJSON)
51+
target_include_directories(main PUBLIC
52+
${CMAKE_CURRENT_SOURCE_DIR}
53+
${CMAKE_BINARY_DIR}/_deps/rapidjson-src/include
54+
)
55+
add_dependencies(main extract_symbols)

guest/storage/build.sh

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
set -v
2-
clang++-20 -static -O2 -std=c++20 -Wl,-Ttext-segment=0x44000000 storage.cpp -o storage
2+
#clang++-20 -static -O2 -std=c++20 -Wl,-Ttext-segment=0x44000000 storage.cpp -o storage
3+
#
4+
#objcopy -w --extract-symbol --strip-symbol=!remote* --strip-symbol=!_Z*remote* --strip-symbol=* storage storage.syms
5+
#clang++-20 -static -O2 -std=c++20 -Wl,--just-symbols=storage.syms main.cpp -o main
36

4-
objcopy -w --extract-symbol --strip-symbol=!remote* --strip-symbol=* storage storage.syms
5-
clang++-20 -static -O2 -std=c++20 -Wl,--just-symbols=storage.syms main.cpp -o main
7+
mkdir -p .build
8+
pushd .build
9+
cmake .. -DCMAKE_BUILD_TYPE=Release
10+
make -j8
11+
popd
12+
13+
ln -fs .build/main main
14+
ln -fs .build/storage storage

guest/storage/json.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
#include <rapidjson/allocators.h>
3+
#include <rapidjson/document.h>
4+
#include <rapidjson/prettywriter.h>
5+
#include <rapidjson/stringbuffer.h>
6+
#include <rapidjson/writer.h>
7+
8+
typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<>, rapidjson::MemoryPoolAllocator<>> JsonDocument;

guest/storage/main.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
#include <stdio.h>
2-
extern "C" int remote_function(int(*callback)(int), int value);
1+
#include <cassert>
2+
#include <cstdio>
3+
#include <array>
4+
#include <memory_resource>
5+
#include "json.hpp"
6+
// Test 1: Simple remote function
7+
extern int remote_function(int(*callback)(int), int value);
8+
// Test 2: Remote allocation with polymorphic memory resource
9+
static std::vector<std::byte> buffer(65536);
10+
static std::pmr::monotonic_buffer_resource mbr{buffer.data(), buffer.size()};
11+
extern std::pmr::vector<int> remote_allocation(std::pmr::memory_resource* mr, size_t size);
12+
// Test 3: RapidJSON using same polymorphic memory resource
13+
extern void remote_json(JsonDocument& j);
14+
#define my_assert(x) do { if (!(x)) { printf("Assertion failed: %s\n", #x); std::abort(); } } while(0)
315

416
static int double_int(int value)
517
{
@@ -9,11 +21,61 @@ static int double_int(int value)
921
int main()
1022
{
1123
printf("Hello from Main VM!\n");
12-
fflush(stdout);
13-
for (int i = 0; i < 10; i++) {
14-
const int val = remote_function(double_int, 21);
15-
printf("Returned value: %d\n", val);
24+
if constexpr (true) {
25+
for (int i = 0; i < 10; i++) {
26+
const int val = remote_function(double_int, 21);
27+
my_assert(val == 42);
28+
}
29+
printf("* Verified remote_function works\n");
30+
}
31+
if constexpr (true) {
32+
std::pmr::memory_resource* mr = &mbr;
33+
for (int i = 0; i < 10; i++) {
34+
std::pmr::vector<int> vec = remote_allocation(mr, 1024);
35+
my_assert(!vec.empty());
36+
my_assert(vec.size() == 1024);
37+
for (size_t j = 0; j < vec.size(); j++) {
38+
my_assert(vec[j] == j);
39+
//printf("%d ", vec[j]);
40+
}
41+
}
42+
printf("* Verified remote_allocation works\n");
1643
}
44+
if constexpr (true) {
45+
char valueBuffer[8192];
46+
char parseBuffer[2048];
47+
rapidjson::MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
48+
rapidjson::MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
49+
JsonDocument j(&valueAllocator, sizeof(parseBuffer), &parseAllocator);
50+
remote_json(j);
51+
my_assert(!j.HasParseError());
52+
my_assert(j.IsObject());
53+
my_assert(j.HasMember("key"));
54+
my_assert(j["key"].IsString());
55+
my_assert(strcmp(j["key"].GetString(), "value") == 0);
56+
my_assert(j.HasMember("number"));
57+
my_assert(j["number"].IsInt());
58+
my_assert(j["number"].GetInt() == 42);
59+
my_assert(j.HasMember("array"));
60+
my_assert(j["array"].IsArray());
61+
const auto& arr = j["array"];
62+
my_assert(arr.Size() == 3);
63+
my_assert(arr[0].IsInt() && arr[0].GetInt() == 1);
64+
my_assert(arr[1].IsInt() && arr[1].GetInt() == 2);
65+
my_assert(arr[2].IsInt() && arr[2].GetInt() == 3);
66+
my_assert(j.HasMember("boolean"));
67+
my_assert(j["boolean"].IsBool());
68+
my_assert(j["boolean"].GetBool() == true);
69+
// Pretty print the Document
70+
rapidjson::StringBuffer buffer;
71+
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
72+
writer.SetIndent(' ', 4); // Use 4 spaces for indentation
73+
j.Accept(writer);
74+
printf("Remote JSON document: %s\n", buffer.GetString());
75+
76+
printf("* Verified remote_json works\n");
77+
}
78+
fflush(stdout);
1779
return 0;
1880
}
1981

guest/storage/remote_alloc.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <cstdint>
5+
6+
template<typename T>
7+
struct RemoteAllocator {
8+
using value_type = T;
9+
10+
RemoteAllocator() noexcept {
11+
this->m_fsbase = get_fsbase();
12+
}
13+
14+
template<typename U>
15+
constexpr RemoteAllocator(const RemoteAllocator<U>&) noexcept
16+
: m_fsbase(get_fsbase()) {}
17+
18+
T* allocate(std::size_t n) {
19+
if (n > std::size_t(-1) / sizeof(T))
20+
throw std::bad_alloc();
21+
if (auto p = static_cast<T*>(::operator new(n * sizeof(T))))
22+
return p;
23+
throw std::bad_alloc();
24+
}
25+
26+
void deallocate(T* p, std::size_t) noexcept {
27+
::operator delete(p, std::align_val_t{alignof(T)});
28+
}
29+
30+
private:
31+
uint64_t m_fsbase;
32+
uint64_t get_fsbase() {
33+
uint64_t fsbase;
34+
asm ("rdfsbase %0" : "=r"(fsbase));
35+
return fsbase;
36+
}
37+
void set_fsbase(uint64_t fsbase) {
38+
asm ("wrfsbase %0" :: "r"(fsbase));
39+
}
40+
};

guest/storage/storage.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
1-
#include <stdio.h>
2-
#include <unistd.h>
1+
#include <cstdio>
2+
#include <cstdlib>
3+
#include <memory_resource>
4+
#include "json.hpp"
5+
using namespace rapidjson;
36

4-
extern "C" int remote_function(int (*arg)(int), int value)
7+
extern int remote_function(int (*arg)(int), int value)
58
{
69
//write(1, "In remote_function\n", 20);
710
return arg(value);
811
}
912

13+
extern std::pmr::vector<int> remote_allocation(std::pmr::memory_resource* mr, size_t size)
14+
{
15+
std::pmr::vector<int> vec{mr};
16+
for (size_t i = 0; i < size; i++)
17+
vec.push_back(i);
18+
return vec;
19+
}
20+
21+
extern void remote_json(JsonDocument& j)
22+
{
23+
auto& alloc = j.GetAllocator();
24+
// Create JSON object
25+
j.SetObject();
26+
j.AddMember(Value().SetString("key", alloc), Value().SetString("value", alloc), alloc);
27+
j.AddMember(Value().SetString("number", alloc), 42, alloc);
28+
// Add JSON from document string
29+
JsonDocument d;
30+
d.Parse(R"({"array": [1, 2, 3], "boolean": true})");
31+
assert(!d.HasParseError());
32+
for (auto& m : d.GetObject())
33+
j.AddMember(m.name, m.value, alloc);
34+
}
35+
1036
int main()
1137
{
1238
printf("Hello from Storage!\n");

storage.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ else
2323
exit 1
2424
fi
2525

26+
# Verbose shell
27+
set -x
2628
./build/storagekvm $MAIN $SECONDARY

0 commit comments

Comments
 (0)