1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stdio.h> 6#include <limits.h> 7#include <inttypes.h> 8#include <sys/types.h> 9#include <stdlib.h> 10#include <unistd.h> 11 12#include <zircon/compiler.h> 13#include <zircon/process.h> 14#include <zircon/syscalls.h> 15#include <fbl/algorithm.h> 16 17#include "bench.h" 18 19static zx_ticks_t ns_to_ticks(zx_time_t ns) { 20 __uint128_t temp = (__uint128_t)ns * zx_ticks_per_second() / ZX_SEC(1); 21 return (zx_ticks_t)temp; 22} 23 24static zx_time_t ticks_to_ns(zx_ticks_t ticks) { 25 __uint128_t temp = (__uint128_t)ticks * ZX_SEC(1) / zx_ticks_per_second(); 26 return (zx_time_t)temp; 27} 28 29// spin the cpu a bit to make sure the frequency is cranked to the top 30static void spin(zx_time_t nanosecs) { 31 zx_ticks_t target_ticks = ns_to_ticks(nanosecs); 32 zx_ticks_t t = zx_ticks_get(); 33 34 while (zx_ticks_get() - t < target_ticks) 35 ; 36} 37 38template <typename T> 39inline zx_time_t time_it(T func) { 40 spin(ZX_MSEC(10)); 41 42 zx_ticks_t ticks = zx_ticks_get(); 43 func(); 44 ticks = zx_ticks_get() - ticks; 45 46 return ticks_to_ns(ticks); 47} 48 49int vmo_run_benchmark() { 50 zx_time_t t; 51 //zx_handle_t vmo; 52 53 printf("starting VMO benchmark\n"); 54 55 // allocate a bunch of large vmos, delete them 56 const size_t size = 32*1024*1024; 57 zx_handle_t vmos[32]; 58 uintptr_t ptr; 59 60 t = time_it([&](){ 61 for (auto& vmo : vmos) { 62 zx_vmo_create(size, 0, &vmo); 63 } 64 }); 65 66 printf("\ttook %" PRIu64 " nsecs to create %zu vmos of size %zu\n", t, fbl::count_of(vmos), size); 67 68 t = time_it([&](){ 69 for (auto& vmo : vmos) { 70 zx_handle_close(vmo); 71 } 72 }); 73 printf("\ttook %" PRIu64 " nsecs to delete %zu vmos of size %zu\n", t, fbl::count_of(vmos), size); 74 75 // create a vmo and demand fault it in 76 zx_handle_t vmo; 77 zx_vmo_create(size, 0, &vmo); 78 79 zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &ptr); 80 81 t = time_it([&](){ 82 for (size_t i = 0; i < size; i += PAGE_SIZE) { 83 __UNUSED char a = ((volatile char *)ptr)[i]; 84 } 85 }); 86 printf("\ttook %" PRIu64 " nsecs to read fault in vmo of size %zu (should be read faulting a zero page)\n", t, size); 87 88 t = time_it([&](){ 89 for (size_t i = 0; i < size; i += PAGE_SIZE) { 90 __UNUSED char a = ((volatile char *)ptr)[i]; 91 } 92 }); 93 printf("\ttook %" PRIu64 " nsecs to read in vmo of size %zu a second time (should be mapped already)\n", t, size); 94 95 t = time_it([&](){ 96 for (size_t i = 0; i < size; i += PAGE_SIZE) { 97 ((volatile char *)ptr)[i] = 99; 98 } 99 }); 100 printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu after read faulting it\n", t, size); 101 102 t = time_it([&](){ 103 for (size_t i = 0; i < size; i += PAGE_SIZE) { 104 ((volatile char *)ptr)[i] = 99; 105 } 106 }); 107 printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu a second time\n", t, size); 108 109 // unmap the original mapping 110 t = time_it([&](){ 111 zx_vmar_unmap(zx_vmar_root_self(), ptr, size); 112 }); 113 printf("\ttook %" PRIu64 " nsecs to unmap the vmo %zu (%zu pages)\n", t, size, size / PAGE_SIZE); 114 115 // map it a again and time read faulting it 116 zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &ptr); 117 118 t = time_it([&](){ 119 for (size_t i = 0; i < size; i += PAGE_SIZE) { 120 __UNUSED char a = ((volatile char *)ptr)[i]; 121 } 122 }); 123 printf("\ttook %" PRIu64 " nsecs to read fault in vmo of size %zu in another mapping\n", t, size); 124 125 zx_vmar_unmap(zx_vmar_root_self(), ptr, size); 126 127 // map it a again and time write faulting it 128 zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &ptr); 129 130 t = time_it([&](){ 131 for (size_t i = 0; i < size; i += PAGE_SIZE) { 132 ((volatile char *)ptr)[i] = 99; 133 } 134 }); 135 printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu in another mapping\n", t, size); 136 137 zx_vmar_unmap(zx_vmar_root_self(), ptr, size); 138 139 // delete the vmo 140 t = time_it([&](){ 141 zx_handle_close(vmo); 142 }); 143 printf("\ttook %" PRIu64 " nsecs to delete populated vmo of size %zu\n", t, size); 144 145 // create a second vmo and write fault it in directly 146 zx_vmo_create(size, 0, &vmo); 147 148 zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0, size, &ptr); 149 150 t = time_it([&](){ 151 for (size_t i = 0; i < size; i += PAGE_SIZE) { 152 ((volatile char *)ptr)[i] = 99; 153 } 154 }); 155 printf("\ttook %" PRIu64 " nsecs to write fault in vmo of size %zu\n", t, size); 156 157 zx_handle_close(vmo); 158 159 // create a vmo and commit and decommit it directly 160 zx_vmo_create(size, 0, &vmo); 161 162 t = time_it([&](){ 163 zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT, 0, size, nullptr, 0); 164 }); 165 printf("\ttook %" PRIu64 " nsecs to commit vmo of size %zu\n", t, size); 166 167 t = time_it([&](){ 168 zx_status_t status = zx_vmo_op_range(vmo, ZX_VMO_OP_COMMIT, 0, size, nullptr, 0); 169 if (status != ZX_OK) { 170 __builtin_trap(); 171 } 172 }); 173 printf("\ttook %" PRIu64 " nsecs to commit already committed vmo of size %zu\n", t, size); 174 175 t = time_it([&](){ 176 zx_vmo_op_range(vmo, ZX_VMO_OP_DECOMMIT, 0, size, nullptr, 0); 177 }); 178 printf("\ttook %" PRIu64 " nsecs to decommit vmo of size %zu\n", t, size); 179 180 zx_handle_close(vmo); 181 182 printf("done with benchmark\n"); 183 184 return 0; 185} 186