PX4 Firmware
PX4 Autopilot Software http://px4.io
sd_bench.c
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2016 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file sd_bench.c
36  *
37  * SD Card benchmarking
38  */
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 
45 #include <px4_platform_common/px4_config.h>
46 #include <px4_platform_common/module.h>
47 #include <px4_platform_common/getopt.h>
48 #include <px4_platform_common/log.h>
49 
50 #include <drivers/drv_hrt.h>
51 
52 static void usage(void);
53 
54 /** sequential write speed test */
55 static void write_test(int fd, uint8_t *block, int block_size);
56 
57 /**
58  * Measure the time for fsync.
59  * @param fd
60  * @return time in ms
61  */
62 static inline unsigned int time_fsync(int fd);
63 
64 __EXPORT int sd_bench_main(int argc, char *argv[]);
65 
66 static const char *BENCHMARK_FILE = PX4_STORAGEDIR"/benchmark.tmp";
67 
68 static int num_runs; ///< number of runs
69 static int run_duration; ///< duration of a single run [ms]
70 static bool synchronized; ///< call fsync after each block?
71 
72 static void
74 {
75  PRINT_MODULE_DESCRIPTION("Test the speed of an SD Card");
76 
77  PRINT_MODULE_USAGE_NAME_SIMPLE("sd_bench", "command");
78  PRINT_MODULE_USAGE_PARAM_INT('b', 4096, 1, 1000000, "Block size for each read/write", true);
79  PRINT_MODULE_USAGE_PARAM_INT('r', 5, 1, 1000, "Number of runs", true);
80  PRINT_MODULE_USAGE_PARAM_INT('d', 2000, 1, 100000, "Duration of a run in ms", true);
81  PRINT_MODULE_USAGE_PARAM_FLAG('s', "Call fsync after each block (default=at end of each run)", true);
82 }
83 
84 int
85 sd_bench_main(int argc, char *argv[])
86 {
87  int block_size = 4096;
88  int myoptind = 1;
89  int ch;
90  const char *myoptarg = NULL;
91  synchronized = false;
92  num_runs = 5;
93  run_duration = 2000;
94 
95  while ((ch = px4_getopt(argc, argv, "b:r:d:s", &myoptind, &myoptarg)) != EOF) {
96  switch (ch) {
97  case 'b':
98  block_size = strtol(myoptarg, NULL, 0);
99  break;
100 
101  case 'r':
102  num_runs = strtol(myoptarg, NULL, 0);
103  break;
104 
105  case 'd':
106  run_duration = strtol(myoptarg, NULL, 0);
107  break;
108 
109  case 's':
110  synchronized = true;
111  break;
112 
113  default:
114  usage();
115  return -1;
116  break;
117  }
118  }
119 
120  if (block_size <= 0 || num_runs <= 0) {
121  PX4_ERR("invalid argument");
122  return -1;
123  }
124 
125  int bench_fd = open(BENCHMARK_FILE, O_CREAT | O_WRONLY | O_TRUNC, PX4_O_MODE_666);
126 
127  if (bench_fd < 0) {
128  PX4_ERR("Can't open benchmark file %s", BENCHMARK_FILE);
129  return -1;
130  }
131 
132  //create some data block
133  uint8_t *block = (uint8_t *)malloc(block_size);
134 
135  if (!block) {
136  PX4_ERR("Failed to allocate memory block");
137  close(bench_fd);
138  return -1;
139  }
140 
141  for (int i = 0; i < block_size; ++i) {
142  block[i] = (uint8_t)i;
143  }
144 
145  PX4_INFO("Using block size = %i bytes, sync=%i", block_size, (int)synchronized);
146  write_test(bench_fd, block, block_size);
147 
148  free(block);
149  close(bench_fd);
150  unlink(BENCHMARK_FILE);
151 
152  return 0;
153 }
154 
155 unsigned int time_fsync(int fd)
156 {
157  hrt_abstime fsync_start = hrt_absolute_time();
158  fsync(fd);
159  return hrt_elapsed_time(&fsync_start) / 1000;
160 }
161 
162 void write_test(int fd, uint8_t *block, int block_size)
163 {
164  PX4_INFO("");
165  PX4_INFO("Testing Sequential Write Speed...");
166  double total_elapsed = 0.;
167  unsigned int total_blocks = 0;
168 
169  for (int run = 0; run < num_runs; ++run) {
171  unsigned int num_blocks = 0;
172  unsigned int max_write_time = 0;
173  unsigned int fsync_time = 0;
174 
175  while ((int64_t)hrt_elapsed_time(&start) < run_duration * 1000) {
176 
177  hrt_abstime write_start = hrt_absolute_time();
178  size_t written = write(fd, block, block_size);
179  unsigned int write_time = hrt_elapsed_time(&write_start) / 1000;
180 
181  if (write_time > max_write_time) {
182  max_write_time = write_time;
183  }
184 
185  if ((int)written != block_size) {
186  PX4_ERR("Write error");
187  return;
188  }
189 
190  if (synchronized) {
191  fsync_time += time_fsync(fd);
192  }
193 
194  ++num_blocks;
195  }
196 
197  //Note: if testing a slow device (SD Card) and the OS buffers a lot (eg. Linux),
198  //fsync can take really long, and it looks like the process hangs. But it does
199  //not and the reported result will still be correct.
200  fsync_time += time_fsync(fd);
201 
202  //report
203  double elapsed = hrt_elapsed_time(&start) / 1.e6;
204  PX4_INFO(" Run %2i: %8.2lf KB/s, max write time: %i ms (=%7.2lf KB/s), fsync: %i ms", run,
205  (double)block_size * num_blocks / elapsed / 1024.,
206  max_write_time, (double)block_size / max_write_time * 1000. / 1024., fsync_time);
207 
208  total_elapsed += elapsed;
209  total_blocks += num_blocks;
210  }
211 
212  PX4_INFO(" Avg : %8.2lf KB/s", (double)block_size * total_blocks / total_elapsed / 1024.);
213 }
static int run_duration
duration of a single run [ms]
Definition: sd_bench.c:69
static const char * BENCHMARK_FILE
Definition: sd_bench.c:66
Definition: I2C.hpp:51
static void write_test(int fd, uint8_t *block, int block_size)
sequential write speed test
Definition: sd_bench.c:162
High-resolution timer with callouts and timekeeping.
static int num_runs
number of runs
Definition: sd_bench.c:68
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
static unsigned int time_fsync(int fd)
Measure the time for fsync.
Definition: sd_bench.c:155
__EXPORT int sd_bench_main(int argc, char *argv[])
Definition: sd_bench.c:85
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
Definition: reflect.c:56
int fd
Definition: dataman.cpp:146
static int start()
Definition: dataman.cpp:1452
static void write(bootloader_app_shared_t *pshared)
static void usage(void)
Definition: sd_bench.c:73
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).