1// Copyright 2018 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 <fbl/unique_ptr.h> 6#include <fbl/vector.h> 7#include <lib/zx/resource.h> 8#include <zircon/device/sysinfo.h> 9#include <zircon/status.h> 10#include <zircon/syscalls.h> 11 12#include <assert.h> 13#include <errno.h> 14#include <fcntl.h> 15#include <getopt.h> 16#include <inttypes.h> 17#include <limits.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21#include <threads.h> 22#include <unistd.h> 23 24#include "stress_test.h" 25 26namespace { 27 28zx_status_t get_root_resource(zx::resource* root_resource) { 29 int fd = open("/dev/misc/sysinfo", O_RDWR); 30 if (fd < 0) { 31 fprintf(stderr, "ERROR: Cannot open sysinfo: %s (%d)\n", 32 strerror(errno), errno); 33 return ZX_ERR_NOT_FOUND; 34 } 35 36 zx_handle_t h; 37 ssize_t n = ioctl_sysinfo_get_root_resource(fd, &h); 38 close(fd); 39 40 if (n != sizeof(*root_resource)) { 41 if (n < 0) { 42 fprintf(stderr, "ERROR: Cannot obtain root resource: %s (%zd)\n", 43 zx_status_get_string((zx_status_t)n), n); 44 return (zx_status_t)n; 45 } else { 46 fprintf(stderr, "ERROR: Cannot obtain root resource (%zd != %zd)\n", 47 n, sizeof(root_resource)); 48 return ZX_ERR_NOT_FOUND; 49 } 50 } 51 52 root_resource->reset(h); 53 54 return ZX_OK; 55} 56 57zx_status_t get_kmem_stats(zx_info_kmem_stats_t* kmem_stats) { 58 zx::resource root_resource; 59 zx_status_t ret = get_root_resource(&root_resource); 60 if (ret != ZX_OK) { 61 return ret; 62 } 63 64 zx_status_t err = zx_object_get_info( 65 root_resource.get(), ZX_INFO_KMEM_STATS, kmem_stats, sizeof(*kmem_stats), nullptr, nullptr); 66 if (err != ZX_OK) { 67 fprintf(stderr, "ZX_INFO_KMEM_STATS returns %d (%s)\n", 68 err, zx_status_get_string(err)); 69 return err; 70 } 71 72 return ZX_OK; 73} 74 75void print_help(char** argv, FILE* f) { 76 fprintf(f, "Usage: %s [options]\n", argv[0]); 77 fprintf(f, "options:\n"); 78 fprintf(f, "\t-h: This help\n"); 79 fprintf(f, "\t-t [time in seconds]: stop all tests after the time has elapsed\n"); 80 fprintf(f, "\t-v: verbose, status output\n"); 81} 82 83} // namespace 84 85int main(int argc, char** argv) { 86 zx_status_t status; 87 88 bool verbose = false; 89 zx::duration run_duration = zx::duration::infinite(); 90 91 int c; 92 while ((c = getopt(argc, argv, "ht:v")) > 0) { 93 switch (c) { 94 case 'h': 95 print_help(argv, stdout); 96 return 0; 97 case 't': { 98 long t = atol(optarg); 99 if (t <= 0) { 100 fprintf(stderr, "bad time argument\n"); 101 print_help(argv, stderr); 102 return 1; 103 } 104 run_duration = zx::sec(t); 105 break; 106 } 107 case 'v': 108 verbose = true; 109 break; 110 default: 111 fprintf(stderr, "Unknown option\n"); 112 print_help(argv, stderr); 113 return 1; 114 } 115 } 116 117 // read some system stats for each test to use 118 zx_info_kmem_stats_t kmem_stats; 119 status = get_kmem_stats(&kmem_stats); 120 if (status != ZX_OK) { 121 fprintf(stderr, "error reading kmem stats\n"); 122 return 1; 123 } 124 125 if (run_duration != zx::duration::infinite()) { 126 printf("Running stress tests for %" PRIu64 " seconds\n", run_duration.to_secs()); 127 } else { 128 printf("Running stress tests continually\n"); 129 } 130 131 // initialize all the tests 132 for (auto& test : StressTest::tests()) { 133 printf("Initializing %s test\n", test->name()); 134 status = test->Init(verbose, kmem_stats); 135 if (status != ZX_OK) { 136 fprintf(stderr, "error initializing test\n"); 137 return 1; 138 } 139 } 140 141 // start all of them 142 for (auto& test : StressTest::tests()) { 143 printf("Starting %s test\n", test->name()); 144 status = test->Start(); 145 if (status != ZX_OK) { 146 fprintf(stderr, "error initializing test\n"); 147 return 1; 148 } 149 } 150 151 // set stdin to non blocking 152 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); 153 154 zx::time start_time = zx::clock::get_monotonic(); 155 bool stop = false; 156 for (;;) { 157 // look for ctrl-c for terminals that do not support it 158 char c; 159 while (read(STDIN_FILENO, &c, 1) > 0) { 160 if (c == 0x3) { 161 stop = true; 162 break; 163 } 164 } 165 if (stop) { 166 break; 167 } 168 169 // wait for a second to try again 170 zx::nanosleep(zx::deadline_after(zx::sec(1))); 171 172 if (run_duration != zx::duration::infinite()) { 173 zx::time now = zx::clock::get_monotonic(); 174 if (now - start_time >= run_duration) { 175 break; 176 } 177 } 178 } 179 180 // shut them down 181 for (auto& test : StressTest::tests()) { 182 printf("Stopping %s test\n", test->name()); 183 status = test->Stop(); 184 if (status != ZX_OK) { 185 fprintf(stderr, "error stopping test\n"); 186 return 1; 187 } 188 } 189 190 return 0; 191} 192