• 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    _MetricMethod(
75        create=pywrap_tfe.TFE_MonitoringNewStringGauge3,
76        delete=pywrap_tfe.TFE_MonitoringDeleteStringGauge3,
77        get_cell=pywrap_tfe.TFE_MonitoringGetCellStringGauge3),
78    _MetricMethod(
79        create=pywrap_tfe.TFE_MonitoringNewStringGauge4,
80        delete=pywrap_tfe.TFE_MonitoringDeleteStringGauge4,
81        get_cell=pywrap_tfe.TFE_MonitoringGetCellStringGauge4),
82]
83_bool_gauge_methods = [
84    _MetricMethod(
85        create=pywrap_tfe.TFE_MonitoringNewBoolGauge0,
86        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge0,
87        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge0),
88    _MetricMethod(
89        create=pywrap_tfe.TFE_MonitoringNewBoolGauge1,
90        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge1,
91        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge1),
92    _MetricMethod(
93        create=pywrap_tfe.TFE_MonitoringNewBoolGauge2,
94        delete=pywrap_tfe.TFE_MonitoringDeleteBoolGauge2,
95        get_cell=pywrap_tfe.TFE_MonitoringGetCellBoolGauge2),
96]
97_sampler_methods = [
98    _MetricMethod(
99        create=pywrap_tfe.TFE_MonitoringNewSampler0,
100        delete=pywrap_tfe.TFE_MonitoringDeleteSampler0,
101        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler0),
102    _MetricMethod(
103        create=pywrap_tfe.TFE_MonitoringNewSampler1,
104        delete=pywrap_tfe.TFE_MonitoringDeleteSampler1,
105        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler1),
106    _MetricMethod(
107        create=pywrap_tfe.TFE_MonitoringNewSampler2,
108        delete=pywrap_tfe.TFE_MonitoringDeleteSampler2,
109        get_cell=pywrap_tfe.TFE_MonitoringGetCellSampler2),
110]
111
112
113class Metric(object):
114  """The base class of metric."""
115
116  __slots__ = ["_metric", "_metric_name", "_metric_methods", "_label_length"]
117
118  def __init__(self, metric_name, metric_methods, label_length, *args):
119    """Creates a new metric.
120
121    Args:
122      metric_name: name of the metric class.
123      metric_methods: list of swig metric methods.
124      label_length: length of label args.
125      *args: the arguments to call create method.
126    """
127    self._metric_name = metric_name
128    self._metric_methods = metric_methods
129    self._label_length = label_length
130
131    if label_length >= len(self._metric_methods):
132      raise ValueError('Cannot create {} metric with label >= {}'.format(
133          self._metric_name, len(self._metric_methods)))
134
135    self._metric = self._metric_methods[self._label_length].create(*args)
136
137  def __del__(self):
138    try:
139      deleter = self._metric_methods[self._label_length].delete
140      metric = self._metric
141    except AttributeError:
142      return
143
144    if deleter is not None:
145      deleter(metric)
146
147  def get_cell(self, *labels):
148    """Retrieves the cell."""
149    if len(labels) != self._label_length:
150      raise ValueError('The {} expects taking {} labels'.format(
151          self._metric_name, self._label_length))
152    return self._metric_methods[self._label_length].get_cell(
153        self._metric, *labels)
154
155
156class CounterCell(object):
157  """CounterCell stores each value of a Counter."""
158
159  __slots__ = ["_cell"]
160
161  def __init__(self, cell):
162    """Creates a new CounterCell.
163
164    Args:
165      cell: A c pointer of TFE_MonitoringCounterCell.
166    """
167    self._cell = cell
168
169  def increase_by(self, value):
170    """Atomically increments the value.
171
172    Args:
173      value: non-negative value.
174    """
175    pywrap_tfe.TFE_MonitoringCounterCellIncrementBy(self._cell, value)
176
177  def value(self):
178    """Retrieves the current value."""
179    return pywrap_tfe.TFE_MonitoringCounterCellValue(self._cell)
180
181
182class Counter(Metric):
183  """A stateful class for updating a cumulative integer metric.
184
185  This class encapsulates a set of values (or a single value for a label-less
186  metric). Each value is identified by a tuple of labels. The class allows the
187  user to increment each value.
188  """
189
190  __slots__ = []
191
192  def __init__(self, name, description, *labels):
193    """Creates a new Counter.
194
195    Args:
196      name: name of the new metric.
197      description: description of the new metric.
198      *labels: The label list of the new metric.
199    """
200    super(Counter, self).__init__('Counter', _counter_methods, len(labels),
201                                  name, description, *labels)
202
203  def get_cell(self, *labels):
204    """Retrieves the cell."""
205    return CounterCell(super(Counter, self).get_cell(*labels))
206
207
208class IntGaugeCell(object):
209  """A single integer value stored in an `IntGauge`."""
210
211  __slots__ = ["_cell"]
212
213  def __init__(self, cell):
214    """Creates a new IntGaugeCell.
215
216    Args:
217      cell: A c pointer of TFE_MonitoringIntGaugeCell.
218    """
219    self._cell = cell
220
221  def set(self, value):
222    """Atomically set the value.
223
224    Args:
225      value: integer value.
226    """
227    pywrap_tfe.TFE_MonitoringIntGaugeCellSet(self._cell, value)
228
229  def value(self):
230    """Retrieves the current value."""
231    return pywrap_tfe.TFE_MonitoringIntGaugeCellValue(self._cell)
232
233
234class IntGauge(Metric):
235  """A stateful class for updating a gauge-like integer metric.
236
237  This class encapsulates a set of integer values (or a single value for a
238  label-less metric). Each value is identified by a tuple of labels. The class
239  allows the user to set each value.
240  """
241
242  __slots__ = []
243
244  def __init__(self, name, description, *labels):
245    """Creates a new IntGauge.
246
247    Args:
248      name: name of the new metric.
249      description: description of the new metric.
250      *labels: The label list of the new metric.
251    """
252    super(IntGauge, self).__init__('IntGauge', _int_gauge_methods, len(labels),
253                                   name, description, *labels)
254
255  def get_cell(self, *labels):
256    """Retrieves the cell."""
257    return IntGaugeCell(super(IntGauge, self).get_cell(*labels))
258
259
260class StringGaugeCell(object):
261  """A single string value stored in an `StringGauge`."""
262
263  __slots__ = ["_cell"]
264
265  def __init__(self, cell):
266    """Creates a new StringGaugeCell.
267
268    Args:
269      cell: A c pointer of TFE_MonitoringStringGaugeCell.
270    """
271    self._cell = cell
272
273  def set(self, value):
274    """Atomically set the value.
275
276    Args:
277      value: string value.
278    """
279    pywrap_tfe.TFE_MonitoringStringGaugeCellSet(self._cell, value)
280
281  def value(self):
282    """Retrieves the current value."""
283    with c_api_util.tf_buffer() as buffer_:
284      pywrap_tfe.TFE_MonitoringStringGaugeCellValue(self._cell, buffer_)
285      value = pywrap_tf_session.TF_GetBuffer(buffer_).decode('utf-8')
286    return value
287
288
289class StringGauge(Metric):
290  """A stateful class for updating a gauge-like string metric.
291
292  This class encapsulates a set of string values (or a single value for a
293  label-less metric). Each value is identified by a tuple of labels. The class
294  allows the user to set each value.
295  """
296
297  __slots__ = []
298
299  def __init__(self, name, description, *labels):
300    """Creates a new StringGauge.
301
302    Args:
303      name: name of the new metric.
304      description: description of the new metric.
305      *labels: The label list of the new metric.
306    """
307    super(StringGauge, self).__init__('StringGauge', _string_gauge_methods,
308                                      len(labels), name, description, *labels)
309
310  def get_cell(self, *labels):
311    """Retrieves the cell."""
312    return StringGaugeCell(super(StringGauge, self).get_cell(*labels))
313
314
315class BoolGaugeCell(object):
316  """A single boolean value stored in an `BoolGauge`."""
317
318  __slots__ = ["_cell"]
319
320  def __init__(self, cell):
321    """Creates a new BoolGaugeCell.
322
323    Args:
324      cell: A c pointer of TFE_MonitoringBoolGaugeCell.
325    """
326    self._cell = cell
327
328  def set(self, value):
329    """Atomically set the value.
330
331    Args:
332      value: bool value.
333    """
334    pywrap_tfe.TFE_MonitoringBoolGaugeCellSet(self._cell, value)
335
336  def value(self):
337    """Retrieves the current value."""
338    return pywrap_tfe.TFE_MonitoringBoolGaugeCellValue(self._cell)
339
340
341@tf_export("__internal__.monitoring.BoolGauge", v1=[])
342class BoolGauge(Metric):
343  """A stateful class for updating a gauge-like bool metric.
344
345  This class encapsulates a set of boolean values (or a single value for a
346  label-less metric). Each value is identified by a tuple of labels. The class
347  allows the user to set each value.
348  """
349
350  __slots__ = []
351
352  def __init__(self, name, description, *labels):
353    """Creates a new BoolGauge.
354
355    Args:
356      name: name of the new metric.
357      description: description of the new metric.
358      *labels: The label list of the new metric.
359    """
360    super(BoolGauge, self).__init__('BoolGauge', _bool_gauge_methods,
361                                    len(labels), name, description, *labels)
362
363  def get_cell(self, *labels):
364    """Retrieves the cell."""
365    return BoolGaugeCell(super(BoolGauge, self).get_cell(*labels))
366
367
368class SamplerCell(object):
369  """SamplerCell stores each value of a Sampler."""
370
371  __slots__ = ["_cell"]
372
373  def __init__(self, cell):
374    """Creates a new SamplerCell.
375
376    Args:
377      cell: A c pointer of TFE_MonitoringSamplerCell.
378    """
379    self._cell = cell
380
381  def add(self, value):
382    """Atomically add a sample.
383
384    Args:
385      value: float value.
386    """
387    pywrap_tfe.TFE_MonitoringSamplerCellAdd(self._cell, value)
388
389  def value(self):
390    """Retrieves the current distribution of samples.
391
392    Returns:
393      A HistogramProto describing the distribution of samples.
394    """
395    with c_api_util.tf_buffer() as buffer_:
396      pywrap_tfe.TFE_MonitoringSamplerCellValue(self._cell, buffer_)
397      proto_data = pywrap_tf_session.TF_GetBuffer(buffer_)
398    histogram_proto = summary_pb2.HistogramProto()
399    histogram_proto.ParseFromString(compat.as_bytes(proto_data))
400    return histogram_proto
401
402
403class Buckets(object):
404  """Bucketing strategies for the samplers."""
405
406  __slots__ = ["buckets"]
407
408  def __init__(self, buckets):
409    """Creates a new Buckets.
410
411    Args:
412      buckets: A c pointer of TFE_MonitoringBuckets.
413    """
414    self.buckets = buckets
415
416  def __del__(self):
417    pywrap_tfe.TFE_MonitoringDeleteBuckets(self.buckets)
418
419
420class ExponentialBuckets(Buckets):
421  """Exponential bucketing strategy.
422
423  Sets up buckets of the form:
424      [-DBL_MAX, ..., scale * growth^i,
425       scale * growth_factor^(i + 1), ..., DBL_MAX].
426  """
427
428  __slots__ = []
429
430  def __init__(self, scale, growth_factor, bucket_count):
431    """Creates a new exponential Buckets.
432
433    Args:
434      scale: float
435      growth_factor: float
436      bucket_count: integer
437    """
438    super(ExponentialBuckets, self).__init__(
439        pywrap_tfe.TFE_MonitoringNewExponentialBuckets(scale, growth_factor,
440                                                       bucket_count))
441
442
443class Sampler(Metric):
444  """A stateful class for updating a cumulative histogram metric.
445
446  This class encapsulates a set of histograms (or a single histogram for a
447  label-less metric) configured with a list of increasing bucket boundaries.
448  Each histogram is identified by a tuple of labels. The class allows the
449  user to add a sample to each histogram value.
450  """
451
452  __slots__ = []
453
454  def __init__(self, name, buckets, description, *labels):
455    """Creates a new Sampler.
456
457    Args:
458      name: name of the new metric.
459      buckets: bucketing strategy of the new metric.
460      description: description of the new metric.
461      *labels: The label list of the new metric.
462    """
463    super(Sampler, self).__init__('Sampler', _sampler_methods, len(labels),
464                                  name, buckets.buckets, description, *labels)
465
466  def get_cell(self, *labels):
467    """Retrieves the cell."""
468    return SamplerCell(super(Sampler, self).get_cell(*labels))
469
470
471class MonitoredTimer(object):
472  """A context manager to measure the walltime and increment a Counter cell."""
473
474  __slots__ = ["cell", "t"]
475
476  def __init__(self, cell):
477    """Creates a new MonitoredTimer.
478
479    Args:
480      cell: the cell associated with the time metric that will be inremented.
481    """
482    self.cell = cell
483
484  def __enter__(self):
485    self.t = time.time()
486    return self
487
488  def __exit__(self, exception_type, exception_value, traceback):
489    del exception_type, exception_value, traceback
490    micro_seconds = (time.time() - self.t) * 1000000
491    self.cell.increase_by(int(micro_seconds))
492
493
494def monitored_timer(cell):
495  """A function decorator for adding MonitoredTimer support.
496
497  Args:
498    cell: the cell associated with the time metric that will be inremented.
499  Returns:
500    A decorator that measure the function runtime and increment the specified
501    counter cell.
502  """
503
504  def actual_decorator(func):
505
506    @functools.wraps(func)
507    def wrapper(*args, **kwargs):
508      with MonitoredTimer(cell):
509        return func(*args, **kwargs)
510
511    return wrapper
512
513  return actual_decorator
514