coverage.py 3.7 KB

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