blob: f6bdfb6ad0cc82d7699b83d4bd6393c6d4b63f94 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <object/message_packet.h>
#include <fbl/unique_ptr.h>
#include <kernel/spinlock.h>
#include <lib/unittest/unittest.h>
#include <lib/unittest/user_memory.h>
#include <lib/user_copy/user_ptr.h>
#include <platform.h>
namespace {
using testing::UserMemory;
static bool bench_create() {
BEGIN_TEST;
constexpr size_t kSize = 65536;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = make_user_in_ptr(mem->in());
constexpr size_t kIterations = 1000000;
zx_time_t time = 0;
zx_time_t total_time = 0;
spin_lock_saved_state_t state;
for (size_t i = 0; i < kIterations; ++i) {
fbl::unique_ptr<MessagePacket> mp;
zx_status_t status = ZX_OK;
arch_interrupt_save(&state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
time = current_time();
{
status = MessagePacket::Create(mem_in, kSize, 0, &mp);
}
total_time += current_time() - time;
arch_interrupt_restore(state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
assert(status == ZX_OK);
mp.reset();
}
printf("took %" PRIu64 " ns per iteration\n",
total_time / kIterations);
END_TEST;
}
static bool bench_copy() {
BEGIN_TEST;
constexpr size_t kSize = 65536;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = make_user_in_ptr(mem->in());
auto mem_out = make_user_out_ptr(mem->out());
constexpr size_t kIterations = 1000000;
zx_time_t time = 0;
zx_time_t total_time = 0;
spin_lock_saved_state_t state;
for (size_t i = 0; i < kIterations; ++i) {
fbl::unique_ptr<MessagePacket> mp;
zx_status_t status = ZX_OK;
status = MessagePacket::Create(mem_in, kSize, 0, &mp);
assert(status == ZX_OK);
arch_interrupt_save(&state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
time = current_time();
{
status = mp->CopyDataTo(mem_out);
}
total_time += current_time() - time;
arch_interrupt_restore(state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
assert(status == ZX_OK);
mp.reset();
}
printf("took %" PRIu64 " ns per iteration\n",
total_time / kIterations);
END_TEST;
}
static bool bench_destroy() {
BEGIN_TEST;
constexpr size_t kSize = 65536;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = make_user_in_ptr(mem->in());
constexpr size_t kIterations = 1000000;
zx_time_t time = 0;
zx_time_t total_time = 0;
spin_lock_saved_state_t state;
for (size_t i = 0; i < kIterations; ++i) {
fbl::unique_ptr<MessagePacket> mp;
zx_status_t status = ZX_OK;
status = MessagePacket::Create(mem_in, kSize, 0, &mp);
assert(status == ZX_OK);
arch_interrupt_save(&state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
time = current_time();
{
mp.reset();
}
total_time += current_time() - time;
arch_interrupt_restore(state, ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS);
}
printf("took %" PRIu64 " ns per iteration\n",
total_time / kIterations);
END_TEST;
}
// Create a MessagePacket and call CopyDataTo.
static bool create() {
BEGIN_TEST;
constexpr size_t kSize = 62234;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = make_user_in_ptr(mem->in());
auto mem_out = make_user_out_ptr(mem->out());
fbl::AllocChecker ac;
auto buf = fbl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check(), "");
memset(buf.get(), 'A', kSize);
ASSERT_EQ(ZX_OK, mem_out.copy_array_to_user(buf.get(), kSize), "");
constexpr uint32_t kNumHandles = 64;
fbl::unique_ptr<MessagePacket> mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(mem_in, kSize, kNumHandles, &mp), "");
ASSERT_EQ(kSize, mp->data_size(), "");
EXPECT_EQ(kNumHandles, mp->num_handles(), "");
EXPECT_NE(0U, mp->get_txid(), "");
auto result_buf = fbl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check(), "");
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out), "");
ASSERT_EQ(ZX_OK, mem_in.copy_array_from_user(result_buf.get(), kSize), "");
EXPECT_EQ(0, memcmp(buf.get(), result_buf.get(), kSize), "");
END_TEST;
}
// Create a MessagePacket via void* and call CopyDataTo.
static bool create_void_star() {
BEGIN_TEST;
constexpr size_t kSize = 4;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(kSize);
auto mem_in = make_user_in_ptr(mem->in());
auto mem_out = make_user_out_ptr(mem->out());
fbl::AllocChecker ac;
auto in_buf = fbl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check(), "");
memset(in_buf.get(), 'B', kSize);
void* in = in_buf.get();
constexpr uint32_t kNumHandles = 0;
fbl::unique_ptr<MessagePacket> mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(in, kSize, kNumHandles, &mp), "");
ASSERT_EQ(kSize, mp->data_size(), "");
EXPECT_EQ(kNumHandles, mp->num_handles(), "");
EXPECT_NE(0U, mp->get_txid(), "");
auto result_buf = fbl::unique_ptr<char[]>(new (&ac) char[kSize]);
ASSERT_TRUE(ac.check(), "");
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out), "");
ASSERT_EQ(ZX_OK, mem_in.copy_array_from_user(result_buf.get(), kSize), "");
EXPECT_EQ(0, memcmp(in_buf.get(), result_buf.get(), kSize), "");
END_TEST;
}
// Create a MessagePacket with zero-length data.
static bool create_zero() {
BEGIN_TEST;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(1);
auto mem_in = make_user_in_ptr(mem->in());
auto mem_out = make_user_out_ptr(mem->out());
fbl::unique_ptr<MessagePacket> mp;
EXPECT_EQ(ZX_OK, MessagePacket::Create(mem_in, 0, 0, &mp), "");
ASSERT_EQ(0U, mp->data_size(), "");
EXPECT_EQ(0U, mp->num_handles(), "");
EXPECT_EQ(0U, mp->get_txid(),"");
ASSERT_EQ(ZX_OK, mp->CopyDataTo(mem_out), "");
END_TEST;
}
// Attempt to create a MessagePacket with too many handles.
static bool create_too_many_handles() {
BEGIN_TEST;
fbl::unique_ptr<UserMemory> mem = UserMemory::Create(1);
auto mem_in = make_user_in_ptr(mem->in());
fbl::unique_ptr<MessagePacket> mp;
EXPECT_EQ(ZX_ERR_OUT_OF_RANGE, MessagePacket::Create(mem_in, 1, 65, &mp), "");
END_TEST;
}
} // namespace
UNITTEST_START_TESTCASE(message_packet_tests)
UNITTEST("bench_create", bench_create)
UNITTEST("bench_copy", bench_copy)
UNITTEST("bench_destroy", bench_destroy)
UNITTEST("create", create)
UNITTEST("create_void_star", create_void_star)
UNITTEST("create_zero", create_zero)
UNITTEST("create_too_many_handles", create_too_many_handles)
UNITTEST_END_TESTCASE(message_packet_tests, "message_packet", "MessagePacket tests");