• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""TensorFlow monitoring APIs."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import collections
22import functools
23import time
24
25from tensorflow.core.framework import summary_pb2
26from tensorflow.python import pywrap_tfe
27from tensorflow.python.client import pywrap_tf_session
28from tensorflow.python.framework import c_api_util
29from tensorflow.python.util import compat
30from tensorflow.python.util.tf_export import tf_export
31
32_MetricMethod = collections.namedtuple('MetricMethod', 'create delete get_cell')
33_counter_methods = [
34    _MetricMethod(
35        create=pywrap_tfe.TFE_MonitoringNewCounter0,
36        delete=pywrap_tfe.TFE_MonitoringDeleteCounter0,
37        get_cell=pywrap_tfe.TFE_MonitoringGetCellCounter0),
38    _MetricMethod(
39        create=pywrap_tfe.TFE_MonitoringNewCounter1,
40        delete=pywrap_tfe.TFE_MonitoringDeleteCounter1,
41        get_cell=pywrap_tfe.TFE_MonitoringGetCellCounter1),
42    _MetricMethod(
43        create=pywrap_tfe.TFE_MonitoringNewCounter2,
44        delete=pywrap_tfe.TFE_MonitoringDeleteCounter2,
45        get_cell=pywrap_tfe.TFE_MonitoringGetCellCounter2),
46]
47_int_gauge_methods = [
48    _MetricMethod(
49        create=pywrap_tfe.TFE_MonitoringNewIntGauge0,
50        delete=pywrap_tfe.TFE_MonitoringDeleteIntGauge0,
51        get_cell=pywrap_tfe.TFE_MonitoringGetCellIntGauge0),
52    _MetricMethod(
53        create=pywrap_tfe.TFE_MonitoringNewIntGauge1,
54        delete=pywrap_tfe.TFE_MonitoringDeleteIntGauge1,
55        get_cell=pywrap_tfe.TFE_MonitoringGetCellIntGauge1),
56    _MetricMethod(
57        create=pywrap_tfe.TFE_MonitoringNewIntGauge2,
58        delete=pywrap_tfe.TFE_MonitoringDeleteIntGauge2,
59        get_cell=pywrap_tfe.TFE_MonitoringGetCellIntGauge2),
60]
61_string_gauge_methods = [
62    _MetricMethod(
63        create=pywrap_tfe.TFE_MonitoringNewStringGauge0,
64        delete=pywrap_tfe.TFE_MonitoringDeleteStringGauge0,
65        get_cell=pywrap_tfe.TFE_MonitoringGetCellStringGauge0),
66    _MetricMethod(
67        create=pywrap_tfe.TFE_MonitoringNewStringGauge1,
68        delete=pywrap_tfe.TFE_MonitoringDeleteStringGauge1,
69        get_cell=pywrap_tfe.TFE_MonitoringGetCellStringGauge1),
70    _MetricMethod(
71        create=pywrap_tfe.TFE_MonitoringNewStringGauge2,
72        delete=pywrap_tfe.TFE_MonitoringDeleteStringGauge2,
73        get_cell=pywrap_tfe.TFE_MonitoringGetCellStringGauge2),
74]
75_bool_gauge_methods = [
76    _MetricMethod(
77        create=pywrap_tfe.TFE_MonitoringNewBoolGauge0,
78        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge0,
79        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge0),
80    _MetricMethod(
81        create=pywrap_tfe.TFE_MonitoringNewBoolGauge1,
82        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge1,
83        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge1),
84    _MetricMethod(
85        create=pywrap_tfe.TFE_MonitoringNewBoolGauge2,
86        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge2,
87        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge2),
88]
89_sampler_methods = [
90    _MetricMethod(
91        create=pywrap_tfe.TFE_MonitoringNewSampler0,
92        delete=pywrap_tfe.TFE_MonitoringDeleteSampler0,
93        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler0),
94    _MetricMethod(
95        create=pywrap_tfe.TFE_MonitoringNewSampler1,
96        delete=pywrap_tfe.TFE_MonitoringDeleteSampler1,
97        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler1),
98    _MetricMethod(
99        create=pywrap_tfe.TFE_MonitoringNewSampler2,
100        delete=pywrap_tfe.TFE_MonitoringDeleteSampler2,
101        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler2),
102]
103
104
105class Metric(object):
106  """The base class of metric."""
107
108  __slots__ = ["_metric", "_metric_name", "_metric_methods", "_label_length"]
109
110  def __init__(self, metric_name, metric_methods, label_length, *args):
111    """Creates a new metric.
112
113    Args:
114      metric_name: name of the metric class.
115      metric_methods: list of swig metric methods.
116      label_length: length of label args.
117      *args: the arguments to call create method.
118    """
119    self._metric_name = metric_name
120    self._metric_methods = metric_methods
121    self._label_length = label_length
122
123    if label_length >= len(self._metric_methods):
124      raise ValueError('Cannot create {} metric with label >= {}'.format(
125          self._metric_name, len(self._metric_methods)))
126
127    self._metric = self._metric_methods[self._label_length].create(*args)
128
129  def __del__(self):
130    try:
131      deleter = self._metric_methods[self._label_length].delete
132      metric = self._metric
133    except AttributeError:
134      return
135
136    if deleter is not None:
137      deleter(metric)
138
139  def get_cell(self, *labels):
140    """Retrieves the cell."""
141    if len(labels) != self._label_length:
142      raise ValueError('The {} expects taking {} labels'.format(
143          self._metric_name, self._label_length))
144    return self._metric_methods[self._label_length].get_cell(
145        self._metric, *labels)
146
147
148class CounterCell(object):
149  """CounterCell stores each value of a Counter."""
150
151  __slots__ = ["_cell"]
152
153  def __init__(self, cell):
154    """Creates a new CounterCell.
155
156    Args:
157      cell: A c pointer of TFE_MonitoringCounterCell.
158    """
159    self._cell = cell
160
161  def increase_by(self, value):
162    """Atomically increments the value.
163
164    Args:
165      value: non-negative value.
166    """
167    pywrap_tfe.TFE_MonitoringCounterCellIncrementBy(self._cell, value)
168
169  def value(self):
170    """Retrieves the current value."""
171    return pywrap_tfe.TFE_MonitoringCounterCellValue(self._cell)
172
173
174class Counter(Metric):
175  """A stateful class for updating a cumulative integer metric.
176
177  This class encapsulates a set of values (or a single value for a label-less
178  metric). Each value is identified by a tuple of labels. The class allows the
179  user to increment each value.
180  """
181
182  __slots__ = []
183
184  def __init__(self, name, description, *labels):
185    """Creates a new Counter.
186
187    Args:
188      name: name of the new metric.
189      description: description of the new metric.
190      *labels: The label list of the new metric.
191    """
192    super(Counter, self).__init__('Counter', _counter_methods, len(labels),
193                                  name, description, *labels)
194
195  def get_cell(self, *labels):
196    """Retrieves the cell."""
197    return CounterCell(super(Counter, self).get_cell(*labels))
198
199
200class IntGaugeCell(object):
201  """A single integer value stored in an `IntGauge`."""
202
203  __slots__ = ["_cell"]
204
205  def __init__(self, cell):
206    """Creates a new IntGaugeCell.
207
208    Args:
209      cell: A c pointer of TFE_MonitoringIntGaugeCell.
210    """
211    self._cell = cell
212
213  def set(self, value):
214    """Atomically set the value.
215
216    Args:
217      value: integer value.
218    """
219    pywrap_tfe.TFE_MonitoringIntGaugeCellSet(self._cell, value)
220
221  def value(self):
222    """Retrieves the current value."""
223    return pywrap_tfe.TFE_MonitoringIntGaugeCellValue(self._cell)
224
225
226class IntGauge(Metric):
227  """A stateful class for updating a gauge-like integer metric.
228
229  This class encapsulates a set of integer values (or a single value for a
230  label-less metric). Each value is identified by a tuple of labels. The class
231  allows the user to set each value.
232  """
233
234  __slots__ = []
235
236  def __init__(self, name, description, *labels):
237    """Creates a new IntGauge.
238
239    Args:
240      name: name of the new metric.
241      description: description of the new metric.
242      *labels: The label list of the new metric.
243    """
244    super(IntGauge, self).__init__('IntGauge', _int_gauge_methods, len(labels),
245                                   name, description, *labels)
246
247  def get_cell(self, *labels):
248    """Retrieves the cell."""
249    return IntGaugeCell(super(IntGauge, self).get_cell(*labels))
250
251
252class StringGaugeCell(object):
253  """A single string value stored in an `StringGauge`."""
254
255  __slots__ = ["_cell"]
256
257  def __init__(self, cell):
258    """Creates a new StringGaugeCell.
259
260    Args:
261      cell: A c pointer of TFE_MonitoringStringGaugeCell.
262    """
263    self._cell = cell
264
265  def set(self, value):
266    """Atomically set the value.
267
268    Args:
269      value: string value.
270    """
271    pywrap_tfe.TFE_MonitoringStringGaugeCellSet(self._cell, value)
272
273  def value(self):
274    """Retrieves the current value."""
275    with c_api_util.tf_buffer() as buffer_:
276      pywrap_tfe.TFE_MonitoringStringGaugeCellValue(self._cell, buffer_)
277      value = pywrap_tf_session.TF_GetBuffer(buffer_).decode('utf-8')
278    return value
279
280
281class StringGauge(Metric):
282  """A stateful class for updating a gauge-like string metric.
283
284  This class encapsulates a set of string values (or a single value for a
285  label-less metric). Each value is identified by a tuple of labels. The class
286  allows the user to set each value.
287  """
288
289  __slots__ = []
290
291  def __init__(self, name, description, *labels):
292    """Creates a new StringGauge.
293
294    Args:
295      name: name of the new metric.
296      description: description of the new metric.
297      *labels: The label list of the new metric.
298    """
299    super(StringGauge, self).__init__('StringGauge', _string_gauge_methods,
300                                      len(labels), name, description, *labels)
301
302  def get_cell(self, *labels):
303    """Retrieves the cell."""
304    return StringGaugeCell(super(StringGauge, self).get_cell(*labels))
305
306
307class BoolGaugeCell(object):
308  """A single boolean value stored in an `BoolGauge`."""
309
310  __slots__ = ["_cell"]
311
312  def __init__(self, cell):
313    """Creates a new BoolGaugeCell.
314
315    Args:
316      cell: A c pointer of TFE_MonitoringBoolGaugeCell.
317    """
318    self._cell = cell
319
320  def set(self, value):
321    """Atomically set the value.
322
323    Args:
324      value: bool value.
325    """
326    pywrap_tfe.TFE_MonitoringBoolGaugeCellSet(self._cell, value)
327
328  def value(self):
329    """Retrieves the current value."""
330    return pywrap_tfe.TFE_MonitoringBoolGaugeCellValue(self._cell)
331
332
333@tf_export("__internal__.monitoring.BoolGauge", v1=[])
334class BoolGauge(Metric):
335  """A stateful class for updating a gauge-like bool metric.
336
337  This class encapsulates a set of boolean values (or a single value for a
338  label-less metric). Each value is identified by a tuple of labels. The class
339  allows the user to set each value.
340  """
341
342  __slots__ = []
343
344  def __init__(self, name, description, *labels):
345    """Creates a new BoolGauge.
346
347    Args:
348      name: name of the new metric.
349      description: description of the new metric.
350      *labels: The label list of the new metric.
351    """
352    super(BoolGauge, self).__init__('BoolGauge', _bool_gauge_methods,
353                                    len(labels), name, description, *labels)
354
355  def get_cell(self, *labels):
356    """Retrieves the cell."""
357    return BoolGaugeCell(super(BoolGauge, self).get_cell(*labels))
358
359
360class SamplerCell(object):
361  """SamplerCell stores each value of a Sampler."""
362
363  __slots__ = ["_cell"]
364
365  def __init__(self, cell):
366    """Creates a new SamplerCell.
367
368    Args:
369      cell: A c pointer of TFE_MonitoringSamplerCell.
370    """
371    self._cell = cell
372
373  def add(self, value):
374    """Atomically add a sample.
375
376    Args:
377      value: float value.
378    """
379    pywrap_tfe.TFE_MonitoringSamplerCellAdd(self._cell, value)
380
381  def value(self):
382    """Retrieves the current distribution of samples.
383
384    Returns:
385      A HistogramProto describing the distribution of samples.
386    """
387    with c_api_util.tf_buffer() as buffer_:
388      pywrap_tfe.TFE_MonitoringSamplerCellValue(self._cell, buffer_)
389      proto_data = pywrap_tf_session.TF_GetBuffer(buffer_)
390    histogram_proto = summary_pb2.HistogramProto()
391    histogram_proto.ParseFromString(compat.as_bytes(proto_data))
392    return histogram_proto
393
394
395class Buckets(object):
396  """Bucketing strategies for the samplers."""
397
398  __slots__ = ["buckets"]
399
400  def __init__(self, buckets):
401    """Creates a new Buckets.
402
403    Args:
404      buckets: A c pointer of TFE_MonitoringBuckets.
405    """
406    self.buckets = buckets
407
408  def __del__(self):
409    pywrap_tfe.TFE_MonitoringDeleteBuckets(self.buckets)
410
411
412class ExponentialBuckets(Buckets):
413  """Exponential bucketing strategy.
414
415  Sets up buckets of the form:
416      [-DBL_MAX, ..., scale * growth^i,
417       scale * growth_factor^(i + 1), ..., DBL_MAX].
418  """
419
420  __slots__ = []
421
422  def __init__(self, scale, growth_factor, bucket_count):
423    """Creates a new exponential Buckets.
424
425    Args:
426      scale: float
427      growth_factor: float
428      bucket_count: integer
429    """
430    super(ExponentialBuckets, self).__init__(
431        pywrap_tfe.TFE_MonitoringNewExponentialBuckets(scale, growth_factor,
432                                                       bucket_count))
433
434
435class Sampler(Metric):
436  """A stateful class for updating a cumulative histogram metric.
437
438  This class encapsulates a set of histograms (or a single histogram for a
439  label-less metric) configured with a list of increasing bucket boundaries.
440  Each histogram is identified by a tuple of labels. The class allows the
441  user to add a sample to each histogram value.
442  """
443
444  __slots__ = []
445
446  def __init__(self, name, buckets, description, *labels):
447    """Creates a new Sampler.
448
449    Args:
450      name: name of the new metric.
451      buckets: bucketing strategy of the new metric.
452      description: description of the new metric.
453      *labels: The label list of the new metric.
454    """
455    super(Sampler, self).__init__('Sampler', _sampler_methods, len(labels),
456                                  name, buckets.buckets, description, *labels)
457
458  def get_cell(self, *labels):
459    """Retrieves the cell."""
460    return SamplerCell(super(Sampler, self).get_cell(*labels))
461
462
463class MonitoredTimer(object):
464  """A context manager to measure the walltime and increment a Counter cell."""
465
466  __slots__ = ["cell", "t"]
467
468  def __init__(self, cell):
469    """Creates a new MonitoredTimer.
470
471    Args:
472      cell: the cell associated with the time metric that will be inremented.
473    """
474    self.cell = cell
475
476  def __enter__(self):
477    self.t = time.time()
478    return self
479
480  def __exit__(self, exception_type, exception_value, traceback):
481    del exception_type, exception_value, traceback
482    micro_seconds = (time.time() - self.t) * 1000000
483    self.cell.increase_by(int(micro_seconds))
484
485
486def monitored_timer(cell):
487  """A function decorator for adding MonitoredTimer support.
488
489  Args:
490    cell: the cell associated with the time metric that will be inremented.
491  Returns:
492    A decorator that measure the function runtime and increment the specified
493    counter cell.
494  """
495
496  def actual_decorator(func):
497
498    @functools.wraps(func)
499    def wrapper(*args, **kwargs):
500      with MonitoredTimer(cell):
501        return func(*args, **kwargs)
502
503    return wrapper
504
505  return actual_decorator
506