class_docstr: Context-based general purpose meter.
  
  Usage
  -----
  1. In high level code, call :meth:`add_callback` to install a hook that defines an
     activity
  2. In low level code, typically many stack levels below, log quantitative events
     (e.g. elapsed time, transferred bytes, etc.) so that they will be attributed to
     the high-level code calling it, either with :meth:`meter`,
     :meth:`meter_function`, or :meth:`digest_metric`.
  
  Examples
  --------
  In the code that e.g. sends a Python object from A to B over the network:
  >>> from distributed.metrics import context_meter
  >>> with context_meter.add_callback(partial(print, "A->B comms:")):
  ...     await send_over_the_network(obj)
  
  In the serialization utilities, called many stack levels below:
  >>> with context_meter.meter("dumps"):
  ...     pik = pickle.dumps(obj)
  >>> with context_meter.meter("compress"):
  ...     pik = lz4.compress(pik)
  
  And finally, elsewhere, deep into the TCP stack:
  >>> with context_meter.meter("network-write"):
  ...     await comm.write(frames)
  
  When you call the top-level code, you'll get::
    A->B comms: dumps 0.012 seconds
    A->B comms: compress 0.034 seconds
    A->B comms: network-write 0.567 seconds
class_docstr_tok: ["Context-based","general","purpose","meter",".","Usage","--","--","-","1",".","In","high","level","code",",","call",":","meth",":","`","add_callback","`","to","install","a","hook","that","defines","an","activity","2",".","In","low","level","code",",","typically","many","stack","levels","below",",","log","quantitative","events","(","e.g",".","elapsed","time",",","transferred","bytes",",","etc",".",")","so","that","they","will","be","attributed","to","the","high-level","code","calling","it",",","either","with",":","meth",":","`","meter","`",",",":","meth",":","`","meter_function","`",",","or",":","meth",":","`","digest_metric","`",".","Examples","--","--","--","--","In","the","code","that","e.g",".","sends","a","Python","object","from","A","to","B","over","the","network",":",">",">",">","from","distributed.metrics","import","context_meter",">",">",">","with","context_meter.add_callback","(","partial","(","print",",","``","A-",">","B","comms",":","''",")",")",":","...","await","send_over_the_network","(","obj",")","In","the","serialization","utilities",",","called","many","stack","levels","below",":",">",">",">","with","context_meter.meter","(","``","dumps","''",")",":","...","pik","=","pickle.dumps","(","obj",")",">",">",">","with","context_meter.meter","(","``","compress","''",")",":","...","pik","=","lz4.compress","(","pik",")","And","finally",",","elsewhere",",","deep","into","the","TCP","stack",":",">",">",">","with","context_meter.meter","(","``","network-write","''",")",":","...","await","comm.write","(","frames",")","When","you","call","the","top-level","code",",","you","'ll","get",":",":","A-",">","B","comms",":","dumps","0.012","seconds","A-",">","B","comms",":","compress","0.034","seconds","A-",">","B","comms",":","network-write","0.567","seconds"]
docstr: Convenience context manager or decorator which calls func() before and after
  the wrapped code, calculates the delta, and finally calls :meth:`digest_metric`.
  
  If unit=='seconds', it also subtracts any other calls to :meth:`meter` or
  :meth:`digest_metric` with the same unit performed within the context, so that
  the total is strictly additive.
  
  Parameters
  ----------
  label: Hashable
      label to pass to the callback
  unit: str, optional
      unit to pass to the callback. Default: seconds
  func: callable
      see :func:`meter`
  floor: bool, optional
      see :func:`meter`
  
  Yields
  ------
  :class:`MeterOutput` where the ``start`` attribute is populated straight away,
  while ``stop`` and ``delta`` are nan until context exit. In case of multiple
  nested calls to :meth:`meter`, then delta (for seconds only) is reduced by the
  inner metrics, to a minimum of ``floor``.
docstr_tok: ["Convenience","context","manager","or","decorator","which","calls","func","(",")","before","and","after","the","wrapped","code",",","calculates","the","delta",",","and","finally","calls",":","meth",":","`","digest_metric","`",".","If","unit=='seconds","'",",","it","also","subtracts","any","other","calls","to",":","meth",":","`","meter","`","or",":","meth",":","`","digest_metric","`","with","the","same","unit","performed","within","the","context",",","so","that","the","total","is","strictly","additive",".","Parameters","--","--","--","--","--","label",":","Hashable","label","to","pass","to","the","callback","unit",":","str",",","optional","unit","to","pass","to","the","callback",".","Default",":","seconds","func",":","callable","see",":","func",":","`","meter","`","floor",":","bool",",","optional","see",":","func",":","`","meter","`","Yields","--","--","--",":","class",":","`","MeterOutput","`","where","the","``","start","``","attribute","is","populated","straight","away",",","while","``","stop","``","and","``","delta","``","are","nan","until","context","exit",".","In","case","of","multiple","nested","calls","to",":","meth",":","`","meter","`",",","then","delta","(","for","seconds","only",")","is","reduced","by","the","inner","metrics",",","to","a","minimum","of","``","floor","``","."]
code: def meter(
      self,
      label: Hashable,
      unit: str = "seconds",
      func: Callable[[], float] = timemod.perf_counter,
      floor: float | Literal[False] = 0.0,
  ) -> Iterator[MeterOutput]:
      """Convenience context manager or decorator which calls func() before and after
      the wrapped code, calculates the delta, and finally calls :meth:`digest_metric`.
  
      If unit=='seconds', it also subtracts any other calls to :meth:`meter` or
      :meth:`digest_metric` with the same unit performed within the context, so that
      the total is strictly additive.
  
      Parameters
      ----------
      label: Hashable
          label to pass to the callback
      unit: str, optional
          unit to pass to the callback. Default: seconds
      func: callable
          see :func:`meter`
      floor: bool, optional
          see :func:`meter`
  
      Yields
      ------
      :class:`MeterOutput` where the ``start`` attribute is populated straight away,
      while ``stop`` and ``delta`` are nan until context exit. In case of multiple
      nested calls to :meth:`meter`, then delta (for seconds only) is reduced by the
      inner metrics, to a minimum of ``floor``.
      """
      if unit != "seconds":
          try:
              with meter(func, floor=floor) as m:
                  yield m
          finally:
              self.digest_metric(label, m.delta, unit)
          return
  
      # If unit=="seconds", subtract time metered from the sub-contexts
      offsets = []
  
      def callback(label2: Hashable, value2: float, unit2: str) -> None:
          if unit2 == unit:
              # This must be threadsafe to support callbacks invoked from
              # distributed.utils.offload; '+=' on a float would not be threadsafe!
              offsets.append(value2)
  
      try:
          with self.add_callback(callback), meter(
              func, floor=False
          ) as m:
              yield m
      finally:
          delta = m.delta - sum(offsets)
          if floor is not False:
              delta = max(floor, delta)
          m.delta = delta
          self.digest_metric(label, delta, unit)
  
imports: from __future__ import annotations
  import asyncio
  import collections
  import threading
  import time
  from collections.abc import Callable, Hashable, Iterator
  from contextlib import contextmanager
  from contextvars import ContextVar
  from dataclasses import dataclass
  from functools import wraps
  from math import nan
  from typing import Literal
  import psutil
  from distributed.compatibility import WINDOWS
label_desc: Use image node_id 7 for calling the ContextMeter obj's underlying member method code with example usage: obj.meter(label, unit, func, floor) without return types