1/* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2010-2011 Gene Cumm 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 8 * Boston MA 02111-1307, USA; either version 2 of the License, or 9 * (at your option) any later version; incorporated herein by reference. 10 * 11 * ----------------------------------------------------------------------- */ 12 13/* 14 * cptime.c Version 1.4 15 * 16 * Timed copy; read entire file then output total time, bytes transferred, 17 * and compute transfer rate. 18 * 19 * cptime [-s|-l] [-v|-q] [-b _SIZE_] [-n _LEN_] _FILE_... 20 * -s Change to simple output mode without computing transfer rate 21 * -l Change to long output mode (to allow for overriding previous -s) 22 * -v Verbose output 23 * -q Quiet output 24 * -b _SIZE_ use _SIZE_ for transfer size 25 * -n _LEN_ maximum length to fetch 26 * _FILE_... Space delimited list of files to dump 27 * Note: The last instance of -s or -l wins, along with the last use of -b and -n and the winning option will be applied to all operations 28 * 29 * Hisory: 30 * 1.4 Use fread() rather than read(); use CLK_TCK when available. 31 * 1.3 Added -v/-q; rework some argument processing. 32 * 1.2 Added -n 33 * 1.1 Added -l and -b switches; more flexible command line processing 34 * 1.0 First release 35 */ 36 37/* 38 * ToDos: 39 * - Refine timing to be more precise. Low priority. 40 * - Add -o for offset. Wishlist. 41 */ 42 43#include <stdio.h> 44#include <stdlib.h> 45#include <errno.h> 46#include <fcntl.h> 47#include <unistd.h> 48#include <sys/times.h> 49#include <consoles.h> 50#include <minmax.h> 51#include <limits.h> 52#include <string.h> 53#include <stdint.h> 54#include <console.h> 55 56#ifdef __COM32__ 57# define BUFSZ_DEF (size_t)2048 58/* What's optimal? Under 4k? 59 * layout.inc: xfer_buf_seg equ 1000h 60 * com32.inc: push dword (1 << 16) ; 64K bounce buffer 61 */ 62/* typedef size_t off_t */ 63 64# define TPS_T float 65# ifdef CLK_TCK 66static inline TPS_T get_tps(void) { return CLK_TCK; } 67# else 68static inline TPS_T get_tps(void) { return 18.2; } 69# endif 70 71#else /* __COM32__ */ 72 73# define BUFSZ_DEF (size_t)16384 74/* Need to check what might be a "best" buffer/fetch block size here */ 75 76# define TPS_T long 77static inline TPS_T get_tps(void) { return sysconf(_SC_CLK_TCK); } 78 79#endif /* __COM32__ */ 80 81#ifndef SSIZE_MAX 82# define SSIZE_MAX PTRDIFF_MAX 83#endif 84/* typedef ptrdiff_t ssize_t; */ 85#define BUFSZ_MAX (size_t)SSIZE_MAX 86/* ssize_t max */ 87#define BUFSZ_MIN (size_t)1 88 89 90/* Please note: I don't know the origin of these two macros nor their license */ 91#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) 92#define TYPE_MAX(t) \ 93 ((t) (! TYPE_SIGNED (t) \ 94 ? (t) -1 \ 95 : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) 96 97#ifndef OFF_T_MAX 98# define OFF_T_MAX TYPE_MAX(off_t) 99#endif 100/* Can't be SIZE_MAX or SSIZE_MAX as Syslinux/COM32 is unsigned while Linux 101 * is signed. 102 */ 103 104#define LEN_MAX OFF_T_MAX 105/* off_t max */ 106#define LEN_MIN (off_t)0 107 108void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs) 109{ 110 size_t dr; 111 /* prevent divide by 0 */ 112 dr = max(bcnt, (bcnt * tps)) / max((clock_t)1, (et + offs)); 113 printf(" %+d %zu B/s; %zu KiB/s; %zu MiB/s\n", offs, dr, dr/1024, dr/1048576); 114} /* void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs) */ 115 116void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose) 117{ 118 TPS_T tps; 119 if (do_verbose > 2) 120 printf("Enter print_cp_result_long()\n"); 121 tps = get_tps(); 122 printf(" %zu B in %d ticks from '%s'\n", bcnt, (int)(ec - bc), fn); 123 printf(" ~%d ticks per second; %zu B block/transfer size\n", (int)tps, bufsz); 124 print_cp_result_tick(bcnt, (ec - bc), tps, 0); 125 print_cp_result_tick(bcnt, (ec - bc), tps, 1); 126 print_cp_result_tick(bcnt, (ec - bc), tps, -1); 127} /* void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz) */ 128 129void print_cp_result_simple(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose) 130{ 131 if (do_verbose) {} 132 printf(" %zuB %dt %zux '%s'\n", bcnt, (int)(ec - bc), bufsz, fn); 133} /* void print_cp_result_simple(char *fn, int bcnt, clock_t bc, clock_t ec, char do_verbose) */ 134 135size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen) 136{ 137 return min(bufsz, (maxlen - bcnt)); 138} /* size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen) */ 139 140int time_copy(char *fn, char do_simple, char do_verbose, size_t ibufsz, off_t maxlen) 141{ 142// int fd; 143 int rv = 0; 144 int i = 0; 145 FILE *f; 146 size_t bufsz, bcnt = 0; 147 int numrd; 148 struct tms tm; 149 clock_t bc, ec; 150 char buf[ibufsz + 1]; 151 152 buf[0] = 0; 153 if (do_verbose) 154 printf("Trying file '%s'\n", fn); 155 errno = 0; 156// fd = open(fn, O_RDONLY); 157 f = fopen(fn, "r"); 158// if (fd == -1) { 159 if (!f) { 160 switch (errno) { 161 case ENOENT : 162 printf("File '%s' does not exist\n", fn); 163 break; 164 case EBADF: 165 printf("File '%s': Bad File Descriptor\n", fn); 166 break; 167 default : 168 printf("Error '%d' opening file '%s'\n", errno, fn); 169 } 170 rv = 1; 171 } else { 172 if (do_verbose) 173 printf("File '%s' opened\n", fn); 174 bufsz = time_copy_bufsz(ibufsz, bcnt, maxlen); 175 bc = times(&tm); 176// numrd = read(fd, buf, bufsz); 177// numrd = fread(buf, bufsz, 1, f); 178 numrd = fread(buf, 1, bufsz, f); 179 i++; 180 if (numrd > 0) 181 bcnt = numrd; 182 while ((numrd > 0) && (bufsz > 0)) { 183 bufsz = time_copy_bufsz(bufsz, bcnt, maxlen); 184// numrd = read(fd, buf, bufsz); 185// numrd = fread(buf, bufsz, 1, f); 186 numrd = fread(buf, 1, bufsz, f); 187 i++; 188 if (numrd >= 0) 189// bcnt = bcnt + numrd; 190 bcnt += numrd; 191 } 192 ec = times(&tm); 193// close(fd); 194 fclose(f); 195 if (do_verbose) 196 printf("File '%s' closed\n", fn); 197 if (numrd < 0) { 198 switch (errno) { 199 case EIO : 200 printf("IO Error at %zu B reading file '%s'\n", bcnt, fn); 201 break; 202 case EINVAL : 203 printf("Invalid Mode at %zu B reading file '%s'\n", bcnt, fn); 204 break; 205 default : 206 printf("Error '%d' at %zu B reading file '%s'\n", errno, bcnt, fn); 207 } 208 rv = 2; 209 } 210 if (bcnt > 0) { 211 if (bufsz == 0) 212 printf("maxed out on maxln\n"); 213 if (do_simple) 214 print_cp_result_simple(fn, bcnt, bc, ec, ibufsz, do_verbose); 215 else 216 print_cp_result_long(fn, bcnt, bc, ec, ibufsz, do_verbose); 217 } 218 if (do_verbose) 219 printf(" numrd %d bcnt %d bufsz %d i %d\n", numrd, bcnt, bufsz, i); 220 } 221 return rv; 222} /* int time_copy(char *fn, char do_simple, int bufsz, off_t maxlen) */ 223 224int main(int argc, char *argv[]) 225{ 226 int i; 227 char do_simple = 0, do_pbuf = 0, do_plen = 0, do_verbose = 0; 228 char *arg; 229 size_t tbufsz, bufsz = min((BUFSZ_DEF), (BUFSZ_MAX)); 230 off_t tmaxlen, maxlen = LEN_MAX; 231 int numfl = 0; 232 console_ansi_std(); 233// openconsole(&dev_stdcon_r, &dev_stdcon_w); 234 for (i = 1; i < argc; i++) { 235 if (argv[i][0] == '-') { 236 arg = argv[i] + 1; 237 if (strcmp(arg, "b") == 0) { 238 i++; 239 if (i < argc) { 240 tbufsz = atoi(argv[i]); 241 if (tbufsz > 0) 242 bufsz = min(max((BUFSZ_MIN), tbufsz), (BUFSZ_MAX)); 243 do_pbuf = 1; 244 } 245 } else if (strcmp(arg, "n") == 0) { 246 i++; 247 if (i < argc) { 248 tmaxlen = atoi(argv[i]); 249 if (tmaxlen > 0) 250 maxlen = min(max((LEN_MIN), tmaxlen), (LEN_MAX)); 251 do_plen = 1; 252 } 253 } else if (strcmp(arg, "s") == 0) 254 do_simple = 1; 255 else if (strcmp(arg, "l") == 0) 256 do_simple = 0; 257 else if (strcmp(arg, "v") == 0) 258 do_verbose = 1; 259 else if (strcmp(arg, "q") == 0) 260 do_verbose = 0; 261 } 262 } 263 if (do_pbuf || do_verbose) 264 printf("Using bufsz %zu\n", bufsz); 265 if (do_plen || do_verbose) 266 printf("Using maxlen %zu\n", maxlen); 267 for (i = 1; i < argc; i++) { 268 if (argv[i][0] == '-') { 269 arg = argv[i] + 1; 270 if ((strcmp(arg, "b") == 0) || (strcmp(arg, "n") == 0)) 271 i++; /* Skip next arg */ 272 else if (!((strcmp(arg, "s") == 0) || (strcmp(arg, "l") == 0) || (strcmp(arg, "v") == 0) || (strcmp(arg, "q") == 0))) { 273 time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen); 274 numfl++; 275 } 276 } else { 277 time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen); 278 numfl++; 279 } 280 } 281 if (numfl == 0) 282 fprintf(stderr, "%s: Please specify a file\n", argv[0]); 283 return 0; 284} /* int main(int argc, char *argv[]) */ 285