/* Discovering Hard Disk Physical Geometry through Microbenchmarking http://blog.stuffedcow.net/2019/09/hard-disk-geometry-microbenchmarking/ Henry Wong, 2019/09/06 2022/10/12: Fixed overflow in find_next_track_boundary. Add more sanity checks to RPM measurement. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Copy-pasting Tiny Mersenne Twister random number generator from tinymt64.h/c // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html /* * tinymt64 internal state vector and parameters */ struct TINYMT64_T { uint64_t status[2]; uint32_t mat1; uint32_t mat2; uint64_t tmat; }; typedef struct TINYMT64_T tinymt64_t; #ifndef UINT64_C #define UINT64_C(X) (X ## ULL) #endif #define TINYMT64_SH0 12 #define TINYMT64_SH1 11 #define TINYMT64_SH8 8 #define TINYMT64_MASK UINT64_C(0x7fffffffffffffff) #define MIN_LOOP 8 /** * This function changes internal state of tinymt64. * Users should not call this function directly. * @param random tinymt internal status */ inline static void tinymt64_next_state(tinymt64_t * random) { uint64_t x; random->status[0] &= TINYMT64_MASK; x = random->status[0] ^ random->status[1]; x ^= x << TINYMT64_SH0; x ^= x >> 32; x ^= x << 32; x ^= x << TINYMT64_SH1; random->status[0] = random->status[1]; random->status[1] = x; random->status[0] ^= -((int64_t)(x & 1)) & random->mat1; random->status[1] ^= -((int64_t)(x & 1)) & (((uint64_t)random->mat2) << 32); } /** * This function outputs 64-bit unsigned integer from internal state. * Users should not call this function directly. * @param random tinymt internal status * @return 64-bit unsigned pseudorandom number */ inline static uint64_t tinymt64_temper(tinymt64_t * random) { uint64_t x; #if defined(LINEARITY_CHECK) x = random->status[0] ^ random->status[1]; #else x = random->status[0] + random->status[1]; #endif x ^= random->status[0] >> TINYMT64_SH8; x ^= -((int64_t)(x & 1)) & random->tmat; return x; } /** * This function certificate the period of 2^127-1. * @param random tinymt state vector. */ static void period_certification(tinymt64_t * random) { if ((random->status[0] & TINYMT64_MASK) == 0 && random->status[1] == 0) { random->status[0] = 'T'; random->status[1] = 'M'; } } /** * This function initializes the internal state array with a 64-bit * unsigned integer seed. * @param random tinymt state vector. * @param seed a 64-bit unsigned integer used as a seed. */ void tinymt64_init(tinymt64_t * random, uint64_t seed) { random->status[0] = seed ^ ((uint64_t)random->mat1 << 32); random->status[1] = random->mat2 ^ random->tmat; for (int i = 1; i < MIN_LOOP; i++) { random->status[i & 1] ^= i + UINT64_C(6364136223846793005) * (random->status[(i - 1) & 1] ^ (random->status[(i - 1) & 1] >> 62)); } period_certification(random); } inline static uint64_t tinymt64_generate_uint64(tinymt64_t * random) { tinymt64_next_state(random); return tinymt64_temper(random); } // End TinyMT // Older Linux kernels don't have CLOCK_MONOTONIC_RAW, so use CLOCK_MONOTONIC instead. #ifndef CLOCK_MONOTONIC_RAW #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC #endif void help() { // 0 1 2 3 4 5 6 7 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 printf ("Usage: hdubench [options] \n"); printf (" file is usually a block device, because it doesn't make much sense to\n"); printf (" microbenchmark a file on a filesystem.\n"); printf ("\n"); printf ("Options: These change settings and define which tests to run\n"); printf (" --rpm-measure-time