blob: 06cbcaed36543ad045776b883a83edda6c6ffcdd [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 <zircon/compiler.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <fbl/algorithm.h>
#include "bench.h"
static zx_ticks_t ns_to_ticks(zx_time_t ns) {
__uint128_t temp = (__uint128_t)ns * zx_ticks_per_second() / ZX_SEC(1);
return (zx_ticks_t)temp;
}
static zx_time_t ticks_to_ns(zx_ticks_t ticks) {
__uint128_t temp = (__uint128_t)ticks * ZX_SEC(1) / zx_ticks_per_second();
return (zx_time_t)temp;
}
// spin the cpu a bit to make sure the frequency is cranked to the top
static void spin(zx_time_t nanosecs) {
zx_ticks_t target_ticks = ns_to_ticks(nanosecs);
zx_ticks_t t = zx_ticks_get();
while (zx_ticks_get() - t < target_ticks)
;
}
template <typename T>
inline zx_time_t time_it(T func) {
spin(ZX_MSEC(10));
zx_ticks_t ticks = zx_ticks_get();
func();
ticks = zx_ticks_get() - ticks;
return ticks_to_ns(ticks);
}
int vmo_run_benchmark() {
zx_time_t t;
// zx_handle_t vmo;
printf("starting VMO benchmark\n");
// allocate a bunch of large vmos, delete them
const size_t size = 32 * 1024 * 1024;
zx_handle_t vmos[32];
uintptr_t ptr;
t = time_it([&]() {
for (auto &vmo : vmos) {
zx_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) {
zx_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
zx_handle_t vmo;
zx_vmo_create(size, 0, &vmo);
zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &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([&]() { zx_vmar_unmap(zx_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
zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &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);
zx_vmar_unmap(zx_vmar_root_self(), ptr, size);
// map it a again and time write faulting it
zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &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);
zx_vmar_unmap(zx_vmar_root_self(), ptr, size);
// delete the vmo
t = time_it([&]() { zx_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
zx_vmo_create(size, 0, &vmo);
zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &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);
zx_handle_close(vmo);
// create a vmo and commit and decommit it directly
zx_vmo_create(size, 0, &vmo);
t = time_it([&]() { zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT, 0, size, nullptr, 0); });
printf("\ttook %" PRIu64 " nsecs to commit vmo of size %zu\n", t, size);
t = time_it([&]() {
zx_status_t status = zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT, 0, size, nullptr, 0);
if (status != ZX_OK) {
__builtin_trap();
}
});
printf("\ttook %" PRIu64 " nsecs to commit already committed vmo of size %zu\n", t, size);
t = time_it([&]() { zx_vmo_op_range(vmo, ZX_VMO_OP_DECOMMIT, 0, size, nullptr, 0); });
printf("\ttook %" PRIu64 " nsecs to decommit vmo of size %zu\n", t, size);
zx_handle_close(vmo);
printf("done with benchmark\n");
return 0;
}