blob: 9bf1b228f96c366584bbd6deaf094d6f136e9e3d [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <limits.h>
#include <inttypes.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <magenta/compiler.h>
#include <magenta/process.h>
#include <magenta/syscalls.h>
#include <fbl/algorithm.h>
#include "bench.h"
// spin the cpu a bit to make sure the frequency is cranked to the top
static void spin(mx_time_t nanosecs) {
mx_time_t t = mx_time_get(MX_CLOCK_MONOTONIC);
while (mx_time_get(MX_CLOCK_MONOTONIC) - t < nanosecs)
;
}
template <typename T>
inline mx_time_t time_it(T func) {
spin(MX_MSEC(10));
mx_time_t t = mx_time_get(MX_CLOCK_MONOTONIC);
func();
return mx_time_get(MX_CLOCK_MONOTONIC) - t;
}
int vmo_run_benchmark() {
mx_time_t t;
//mx_handle_t vmo;
printf("starting VMO benchmark\n");
// allocate a bunch of large vmos, delete them
const size_t size = 32*1024*1024;
mx_handle_t vmos[32];
uintptr_t ptr;
t = time_it([&](){
for (auto& vmo : vmos) {
mx_vmo_create(size, 0, &vmo);
}
});
printf("\ttook %" PRIu64 " nsecs to create %zu vmos of size %zu\n", t, fbl::count_of(vmos), size);
t = time_it([&](){
for (auto& vmo : vmos) {
mx_handle_close(vmo);
}
});
printf("\ttook %" PRIu64 " nsecs to delete %zu vmos of size %zu\n", t, fbl::count_of(vmos), size);
// create a vmo and demand fault it in
mx_handle_t vmo;
mx_vmo_create(size, 0, &vmo);
mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, size, MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &ptr);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
__UNUSED char a = ((volatile char *)ptr)[i];
}
});
printf("\ttook %" PRIu64 " nsecs to read fault in vmo of size %zu (should be read faulting a zero page)\n", t, size);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
__UNUSED char a = ((volatile char *)ptr)[i];
}
});
printf("\ttook %" PRIu64 " nsecs to read in vmo of size %zu a second time (should be mapped already)\n", t, size);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
((volatile char *)ptr)[i] = 99;
}
});
printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu after read faulting it\n", t, size);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
((volatile char *)ptr)[i] = 99;
}
});
printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu a second time\n", t, size);
// unmap the original mapping
t = time_it([&](){
mx_vmar_unmap(mx_vmar_root_self(), ptr, size);
});
printf("\ttook %" PRIu64 " nsecs to unmap the vmo %zu (%zu pages)\n", t, size, size / PAGE_SIZE);
// map it a again and time read faulting it
mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, size, MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &ptr);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
__UNUSED char a = ((volatile char *)ptr)[i];
}
});
printf("\ttook %" PRIu64 " nsecs to read fault in vmo of size %zu in another mapping\n", t, size);
mx_vmar_unmap(mx_vmar_root_self(), ptr, size);
// map it a again and time write faulting it
mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, size, MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &ptr);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
((volatile char *)ptr)[i] = 99;
}
});
printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu in another mapping\n", t, size);
mx_vmar_unmap(mx_vmar_root_self(), ptr, size);
// delete the vmo
t = time_it([&](){
mx_handle_close(vmo);
});
printf("\ttook %" PRIu64 " nsecs to delete populated vmo of size %zu\n", t, size);
// create a second vmo and write fault it in directly
mx_vmo_create(size, 0, &vmo);
mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, size, MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE, &ptr);
t = time_it([&](){
for (size_t i = 0; i < size; i += PAGE_SIZE) {
((volatile char *)ptr)[i] = 99;
}
});
printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu\n", t, size);
mx_handle_close(vmo);
// create a vmo and commit and decommit it directly
mx_vmo_create(size, 0, &vmo);
t = time_it([&](){
mx_vmo_op_range(vmo, MX_VMO_OP_COMMIT, 0, size, nullptr, 0);
});
printf("\ttook %" PRIu64 " nsecs to commit vmo of size %zu\n", t, size);
uint64_t addrs[size / PAGE_SIZE];
t = time_it([&](){
mx_status_t status = mx_vmo_op_range(vmo, MX_VMO_OP_LOOKUP, 0, size, addrs, sizeof(addrs));
if (status != MX_OK) {
__builtin_trap();
}
});
printf("\ttook %" PRIu64 " nsecs to lookup vmo of size %zu\n", t, size);
t = time_it([&](){
mx_status_t status = mx_vmo_op_range(vmo, MX_VMO_OP_COMMIT, 0, size, nullptr, 0);
if (status != MX_OK) {
__builtin_trap();
}
});
printf("\ttook %" PRIu64 " nsecs to commit already committed vmo of size %zu\n", t, size);
t = time_it([&](){
mx_vmo_op_range(vmo, MX_VMO_OP_DECOMMIT, 0, size, nullptr, 0);
});
printf("\ttook %" PRIu64 " nsecs to decommit vmo of size %zu\n", t, size);
mx_handle_close(vmo);
printf("done with benchmark\n");
return 0;
}