Rework 'get_timer_usec()', use a C++11 clock if possible.

dev_interface.cpp, dev_interface.h, os_win32.cpp: Move function ...
utility.cpp, utility.h: ... to here.
configure.ac: Remove related checks.

git-svn-id: http://svn.code.sf.net/p/smartmontools/code/trunk@5219 4ea69e1a-61f1-4043-bf83-b5c94c648137
pull/99/head
chrfranke 1 year ago
parent 1151fb1b32
commit e662b7486a
  1. 5
      smartmontools/ChangeLog
  2. 12
      smartmontools/atacmds.cpp
  3. 6
      smartmontools/configure.ac
  4. 36
      smartmontools/dev_interface.cpp
  5. 8
      smartmontools/dev_interface.h
  6. 20
      smartmontools/nvmecmds.cpp
  7. 28
      smartmontools/os_win32.cpp
  8. 28
      smartmontools/utility.cpp
  9. 7
      smartmontools/utility.h

@ -2,6 +2,11 @@ $Id$
2021-06-04 Christian Franke <franke@computer.org>
Rework 'get_timer_usec()', use a C++11 clock if possible.
dev_interface.cpp, dev_interface.h, os_win32.cpp: Move function ...
utility.cpp, utility.h: ... to here.
configure.ac: Remove related checks.
ataprint.cpp, nvmeprint.cpp: Add JSON values 'smart_support.*' to
keep consistency with scsiprint.cpp.

@ -4,7 +4,7 @@
* Home page of code is: https://www.smartmontools.org
*
* Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-20 Christian Franke
* Copyright (C) 2008-21 Christian Franke
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
*
@ -563,16 +563,14 @@ int smartcommandhandler(ata_device * device, smart_command_set command, int sele
ata_cmd_out out;
int64_t start_usec = -1;
if (ata_debugmode)
start_usec = smi()->get_timer_usec();
auto start_usec = (ata_debugmode ? get_timer_usec() : -1);
bool ok = device->ata_pass_through(in, out);
if (start_usec >= 0) {
int64_t duration_usec = smi()->get_timer_usec() - start_usec;
if (duration_usec >= 500)
pout(" [Duration: %.3fs]\n", duration_usec / 1000000.0);
auto duration_usec = get_timer_usec() - start_usec;
if (duration_usec > 0)
pout(" [Duration: %.6fs]\n", duration_usec / 1000000.0);
}
if (ata_debugmode && out.out_regs.is_set())

@ -91,10 +91,6 @@ AC_SUBST([svn_deps])
AM_CONDITIONAL(IS_SVN_BUILD, [test "$is_svn_build" = "yes"])
AC_MSG_RESULT([$is_svn_build])
# Note: On Linux, clock_gettime() requires -lrt which implies -lpthreads
# Check omitted for now, gettimeofday() provides reasonable precision
# AC_SEARCH_LIBS(clock_gettime, rt)
# Checks for header files.
AC_CHECK_HEADERS([locale.h])
AC_CHECK_HEADERS([byteswap.h], [], [], [])
@ -131,8 +127,6 @@ AC_TYPE_LONG_DOUBLE_WIDER
AC_CHECK_FUNCS([getopt_long], [need_getopt_long=no], [need_getopt_long=yes])
AM_CONDITIONAL(NEED_GETOPT_LONG, [test "$need_getopt_long" = "yes"])
AC_CHECK_FUNCS([clock_gettime ftime gettimeofday])
# Check byte ordering (defines WORDS_BIGENDIAN)
AC_C_BIGENDIAN

@ -21,12 +21,6 @@
#include <stdlib.h> // realpath()
#include <stdexcept>
#if defined(HAVE_GETTIMEOFDAY)
#include <sys/time.h>
#elif defined(HAVE_FTIME)
#include <sys/timeb.h>
#endif
const char * dev_interface_cpp_cvsid = "$Id$"
DEV_INTERFACE_H_CVSID;
@ -325,36 +319,6 @@ std::string smart_interface::get_app_examples(const char * /*appname*/)
return "";
}
int64_t smart_interface::get_timer_usec()
{
#if defined(HAVE_GETTIMEOFDAY)
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
{
static bool have_clock_monotonic = true;
if (have_clock_monotonic) {
struct timespec ts;
if (!clock_gettime(CLOCK_MONOTONIC, &ts))
return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
have_clock_monotonic = false;
}
}
#endif
{
struct timeval tv;
gettimeofday(&tv, 0);
return tv.tv_sec * 1000000LL + tv.tv_usec;
}
#elif defined(HAVE_FTIME)
{
struct timeb tb;
ftime(&tb);
return tb.time * 1000000LL + tb.millitm * 1000;
}
#else
return -1;
#endif
}
bool smart_interface::disable_system_auto_standby(bool /*disable*/)
{
return set_err(ENOSYS);

@ -3,7 +3,7 @@
*
* Home page of code is: https://www.smartmontools.org
*
* Copyright (C) 2008-20 Christian Franke
* Copyright (C) 2008-21 Christian Franke
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@ -900,12 +900,6 @@ public:
/// TODO: Remove this hack.
virtual std::string get_app_examples(const char * appname);
/// Get microseconds since some unspecified starting point.
/// Used only for command duration measurements in debug outputs.
/// Returns -1 if unsupported.
/// Default implementation uses clock_gettime(), gettimeofday() or ftime().
virtual int64_t get_timer_usec();
/// Disable/Enable system auto standby/sleep mode.
/// Return false if unsupported or if system is running
/// on battery.

@ -3,7 +3,7 @@
*
* Home page of code is: https://www.smartmontools.org
*
* Copyright (C) 2016-20 Christian Franke
* Copyright (C) 2016-21 Christian Franke
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@ -53,8 +53,6 @@ static void debug_hex_dump(const void * data, unsigned size)
static bool nvme_pass_through(nvme_device * device, const nvme_cmd_in & in,
nvme_cmd_out & out)
{
int64_t start_usec = -1;
if (nvme_debugmode) {
pout(" [NVMe call: opcode=0x%02x, size=0x%04x, nsid=0x%08x, cdw10=0x%08x",
in.opcode, in.size, in.nsid, in.cdw10);
@ -62,12 +60,18 @@ static bool nvme_pass_through(nvme_device * device, const nvme_cmd_in & in,
pout(",\n cdw1x=0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
in.cdw11, in.cdw12, in.cdw13, in.cdw14, in.cdw15);
pout("]\n");
start_usec = smi()->get_timer_usec();
}
auto start_usec = (nvme_debugmode ? get_timer_usec() : -1);
bool ok = device->nvme_pass_through(in, out);
if (start_usec >= 0) {
auto duration_usec = get_timer_usec() - start_usec;
if (duration_usec > 0)
pout(" [Duration: %.6fs]\n", duration_usec / 1000000.0);
}
if ( dont_print_serial_number && ok
&& in.opcode == nvme_admin_identify && in.cdw10 == 0x01) {
// Invalidate serial number
@ -76,12 +80,6 @@ static bool nvme_pass_through(nvme_device * device, const nvme_cmd_in & in,
}
if (nvme_debugmode) {
if (start_usec >= 0) {
int64_t duration_usec = smi()->get_timer_usec() - start_usec;
if (duration_usec >= 500)
pout(" [Duration: %.3fs]\n", duration_usec / 1000000.0);
}
if (!ok) {
pout(" [NVMe call failed: ");
if (out.status_valid)

@ -3904,10 +3904,6 @@ public:
virtual std::string get_app_examples(const char * appname) override;
#ifndef __CYGWIN__
virtual int64_t get_timer_usec() override;
#endif
virtual bool disable_system_auto_standby(bool disable) override;
virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
@ -4049,30 +4045,6 @@ std::string win_smart_interface::get_os_version_str()
return vstr;
}
#ifndef __CYGWIN__
// MSVCRT only provides ftime() which uses GetSystemTime()
// This provides only ~15ms resolution by default.
// Use QueryPerformanceCounter instead (~300ns).
// (Cygwin provides CLOCK_MONOTONIC which has the same effect)
int64_t win_smart_interface::get_timer_usec()
{
static int64_t freq = 0;
LARGE_INTEGER t;
if (freq == 0)
freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1);
if (freq <= 0)
return smart_interface::get_timer_usec();
if (!QueryPerformanceCounter(&t))
return -1;
if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000))
return -1;
return (t.QuadPart * 1000000LL) / freq;
}
#endif // __CYGWIN__
ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
{

@ -42,6 +42,19 @@
#include "dev_interface.h"
#include "sg_unaligned.h"
#ifndef USE_CLOCK_MONOTONIC
#ifdef __MINGW32__
// If MinGW-w64 < 9.0.0 or Windows < 8, GetSystemTimeAsFileTime() is used for
// std::chrono::high_resolution_clock. This provides only 1/64s (>15ms) resolution.
// CLOCK_MONOTONIC uses QueryPerformanceCounter() which provides <1us resolution.
#define USE_CLOCK_MONOTONIC 1
#else
// Use std::chrono::high_resolution_clock.
#include <chrono>
#define USE_CLOCK_MONOTONIC 0
#endif
#endif // USE_CLOCK_MONOTONIC
const char * utility_cpp_cvsid = "$Id$"
UTILITY_H_CVSID;
@ -821,6 +834,21 @@ const char * uint128_hilo_to_str(char * str, int strsize, uint64_t value_hi, uin
#endif // HAVE___INT128
// Get microseconds since some unspecified starting point.
long long get_timer_usec()
{
#if USE_CLOCK_MONOTONIC
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts))
return -1;
return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
#else
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
#endif
}
// Runtime check of byte ordering, throws on error.
static void check_endianness()
{

@ -4,7 +4,7 @@
* Home page of code is: https://www.smartmontools.org
*
* Copyright (C) 2002-11 Bruce Allen
* Copyright (C) 2008-20 Christian Franke
* Copyright (C) 2008-21 Christian Franke
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
@ -311,6 +311,11 @@ template <size_t SIZE>
inline const char * uint128_hilo_to_str(char (& str)[SIZE], uint64_t value_hi, uint64_t value_lo)
{ return uint128_hilo_to_str(str, (int)SIZE, value_hi, value_lo); }
/// Get microseconds since some unspecified starting point.
/// Used only for command duration measurements in debug outputs.
/// Returns -1 if unsupported.
long long get_timer_usec();
#ifdef _WIN32
// Get exe directory
//(implemented in os_win32.cpp)

Loading…
Cancel
Save