diff --git a/src/pcp/iostat/pcp-iostat.py b/src/pcp/iostat/pcp-iostat.py index fd049a6f5a7..ccd1265aea0 100755 --- a/src/pcp/iostat/pcp-iostat.py +++ b/src/pcp/iostat/pcp-iostat.py @@ -56,9 +56,18 @@ class IostatReport(pmcc.MetricGroupPrinter): Hcount = 0 def timeStampDelta(self, group): s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec - n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec - # n may be negative here, calculation is still correct. - return s + n / 1000000000.0 + # pmapi timestamps may provide sub-second resolution via tv_nsec (nanoseconds) + # or tv_usec (microseconds) depending on the collector. Prefer nanoseconds + # when available, but gracefully fall back to microseconds to avoid + if hasattr(group.timestamp, 'tv_nsec') and hasattr(group.prevTimestamp, 'tv_nsec'): + n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec + # n may be negative here, calculation is still correct. + return s + n / 1_000_000_000.0 + elif hasattr(group.timestamp, 'tv_usec') and hasattr(group.prevTimestamp, 'tv_usec'): + u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec + return s + u / 1_000_000.0 + # it should not reach here + return s def instlist(self, group, name): return dict(map(lambda x: (x[1], x[2]), group[name].netValues)).keys() diff --git a/src/pcp/mpstat/pcp-mpstat.py b/src/pcp/mpstat/pcp-mpstat.py index 2b0bd59dd4f..85bf2828cc4 100755 --- a/src/pcp/mpstat/pcp-mpstat.py +++ b/src/pcp/mpstat/pcp-mpstat.py @@ -499,8 +499,17 @@ def __init__(self, cpu_util_reporter, total_interrupt_usage_reporter, soft_inter def timeStampDelta(self, group): s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec - n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec - return s + n / 1000000000.0 + # pmapi timestamps may provide sub-second resolution via tv_nsec (nanoseconds) + # or tv_usec (microseconds) depending on the collector. Prefer nanoseconds + # when available, but gracefully fall back to microseconds to avoid + if hasattr(group.timestamp, 'tv_nsec') and hasattr(group.prevTimestamp, 'tv_nsec'): + n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec + return s + n / 1_000_000_000.0 + elif hasattr(group.timestamp, 'tv_usec') and hasattr(group.prevTimestamp, 'tv_usec'): + u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec + return s + u / 1_000_000.0 + # it should not reach here + return s def print_machine_info(self,group, context): self.get_summary_metrics(group) diff --git a/src/pcp/pidstat/pcp-pidstat.py b/src/pcp/pidstat/pcp-pidstat.py index 32bf9256211..813bf912dbc 100755 --- a/src/pcp/pidstat/pcp-pidstat.py +++ b/src/pcp/pidstat/pcp-pidstat.py @@ -925,8 +925,17 @@ class PidstatReport(pmcc.MetricGroupPrinter): def timeStampDelta(self, group): s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec - n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec - return s + n / 1000000000.0 + # pmapi timestamps may provide sub-second resolution via tv_nsec (nanoseconds) + # or tv_usec (microseconds) depending on the collector. Prefer nanoseconds + # when available, but gracefully fall back to microseconds to avoid + if hasattr(group.timestamp, 'tv_nsec') and hasattr(group.prevTimestamp, 'tv_nsec'): + n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec + return s + n / 1_000_000_000.0 + elif hasattr(group.timestamp, 'tv_usec') and hasattr(group.prevTimestamp, 'tv_usec'): + u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec + return s + u / 1_000_000.0 + # it should not reach here + return s def print_machine_info(self,group, context): timestamp = context.pmLocaltime(group.timestamp.tv_sec) diff --git a/src/pcp/ps/pcp-ps.py b/src/pcp/ps/pcp-ps.py index c8f2e9d972b..254be7d4aa2 100755 --- a/src/pcp/ps/pcp-ps.py +++ b/src/pcp/ps/pcp-ps.py @@ -585,8 +585,17 @@ def __init__(self, group=None, options = None): def timeStampDelta(self): s = self.group.timestamp.tv_sec - self.group.prevTimestamp.tv_sec - n = self.group.timestamp.tv_nsec - self.group.prevTimestamp.tv_nsec - return s + n / 1000000000.0 + # pmapi timestamps may provide sub-second resolution via tv_nsec (nanoseconds) + # or tv_usec (microseconds) depending on the collector. Prefer nanoseconds + # when available, but gracefully fall back to microseconds to avoid + if hasattr(self.group.timestamp, 'tv_nsec') and hasattr(self.group.prevTimestamp, 'tv_nsec'): + n = self.group.timestamp.tv_nsec - self.group.prevTimestamp.tv_nsec + return s + n / 1_000_000_000.0 + elif hasattr(self.group.timestamp, 'tv_usec') and hasattr(self.group.prevTimestamp, 'tv_usec'): + u = self.group.timestamp.tv_usec - self.group.prevTimestamp.tv_usec + return s + u / 1_000_000.0 + # it should not reach here + return s def print_machine_info(self,context): timestamp = context.pmLocaltime(self.group.timestamp.tv_sec) diff --git a/src/pcp/tapestat/pcp-tapestat.py b/src/pcp/tapestat/pcp-tapestat.py index dd54c701607..99d0fbcae09 100755 --- a/src/pcp/tapestat/pcp-tapestat.py +++ b/src/pcp/tapestat/pcp-tapestat.py @@ -68,9 +68,18 @@ class TapestatReport(pmcc.MetricGroupPrinter): Hcount = 0 def timeStampDelta(self, group): s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec - n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec - # n may be negative here, calculation is still correct. - return s + n / 1000000000.0 + # pmapi timestamps may provide sub-second resolution via tv_nsec (nanoseconds) + # or tv_usec (microseconds) depending on the collector. Prefer nanoseconds + # when available, but gracefully fall back to microseconds to avoid + if hasattr(group.timestamp, 'tv_nsec') and hasattr(group.prevTimestamp, 'tv_nsec'): + n = group.timestamp.tv_nsec - group.prevTimestamp.tv_nsec + # n may be negative here, calculation is still correct. + return s + n / 1_000_000_000.0 + elif hasattr(group.timestamp, 'tv_usec') and hasattr(group.prevTimestamp, 'tv_usec'): + u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec + return s + u / 1_000_000.0 + # it should not reach here + return s def instlist(self, group, name): return dict(map(lambda x: (x[1], x[2]), group[name].netValues)).keys()