Caffe2 - Python API
A deep learning, cross platform ML framework
coverage.py
1 from __future__ import absolute_import
2 from __future__ import division
3 from __future__ import print_function
4 from __future__ import unicode_literals
5 
6 from caffe2.proto import caffe2_pb2
7 from caffe2.python import core, workspace
8 import os
9 import tempfile
10 from zipfile import ZipFile
11 
12 '''
13 Generates a document in markdown format summrizing the coverage of serialized
14 testing. The document lives in
15 `caffe2/python/serialized_test/SerializedTestCoverage.md`
16 '''
17 
18 OpSchema = workspace.C.OpSchema
19 
20 
21 def gen_serialized_test_coverage(source_dir, output_dir):
22  (covered, not_covered, schemaless) = gen_coverage_sets(source_dir)
23  num_covered = len(covered)
24  num_not_covered = len(not_covered)
25  num_schemaless = len(schemaless)
26  total_ops = num_covered + num_not_covered
27 
28  with open(os.path.join(output_dir, 'SerializedTestCoverage.md'), 'w+') as f:
29  f.write('# Serialized Test Coverage Report\n')
30  f.write("This is an automatically generated file. Please see "
31  "`caffe2/python/serialized_test/README.md` for details. "
32  "In the case of merge conflicts, please rebase and regenerate.\n")
33  f.write('## Summary\n')
34  f.write(
35  'Serialized tests have covered {}/{} ({}%) operators\n\n'.format(
36  num_covered, total_ops,
37  (int)(num_covered / total_ops * 1000) / 10))
38 
39  f.write('## Not covered operators\n')
40  f.write('<details>\n')
41  f.write(
42  '<summary>There are {} not covered operators</summary>\n\n'.format(
43  num_not_covered))
44  for n in sorted(not_covered):
45  f.write('* ' + n + '\n')
46  f.write('</details>\n\n')
47 
48  f.write('## Covered operators\n')
49  f.write('<details>\n')
50  f.write(
51  '<summary>There are {} covered operators</summary>\n\n'.format(
52  num_covered))
53  for n in sorted(covered):
54  f.write('* ' + n + '\n')
55  f.write('</details>\n\n')
56 
57  f.write('## Excluded from coverage statistics\n')
58  f.write('### Schemaless operators\n')
59  f.write('<details>\n')
60  f.write(
61  '<summary>There are {} schemaless operators</summary>\n\n'.format(
62  num_schemaless))
63  for n in sorted(schemaless):
64  f.write('* ' + n + '\n')
65  f.write('</details>\n\n')
66 
67 
68 def gen_coverage_sets(source_dir):
69  covered_ops = gen_covered_ops(source_dir)
70 
71  not_covered_ops = set()
72  schemaless_ops = []
73  for op_name in core._GetRegisteredOperators():
74  s = OpSchema.get(op_name)
75 
76  if s is not None and s.private:
77  continue
78  if s:
79  if op_name not in covered_ops:
80  not_covered_ops.add(op_name)
81  else:
82  if op_name.find("_ENGINE_") == -1:
83  schemaless_ops.append(op_name)
84  return (covered_ops, not_covered_ops, schemaless_ops)
85 
86 
87 def gen_covered_ops(source_dir):
88  def parse_proto(x):
89  proto = caffe2_pb2.OperatorDef()
90  proto.ParseFromString(x)
91  return proto
92 
93  covered = set()
94  for f in os.listdir(source_dir):
95  zipfile = os.path.join(source_dir, f)
96  if not os.path.isfile(zipfile):
97  continue
98  temp_dir = tempfile.mkdtemp()
99  with ZipFile(zipfile) as z:
100  z.extractall(temp_dir)
101  op_path = os.path.join(temp_dir, 'op.pb')
102  with open(op_path, 'rb') as f:
103  loaded_op = f.read()
104  op_proto = parse_proto(loaded_op)
105  covered.add(op_proto.type)
106 
107  index = 0
108  grad_path = os.path.join(temp_dir, 'grad_{}.pb'.format(index))
109  while os.path.isfile(grad_path):
110  with open(grad_path, 'rb') as f:
111  loaded_grad = f.read()
112  grad_proto = parse_proto(loaded_grad)
113  covered.add(grad_proto.type)
114  index += 1
115  grad_path = os.path.join(temp_dir, 'grad_{}.pb'.format(index))
116  return covered