[llvm] r276818 - Retry: [llvm-cov] Add support for exporting coverage data to JSON

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 26 15:50:59 PDT 2016


Author: vedantk
Date: Tue Jul 26 17:50:58 2016
New Revision: 276818

URL: http://llvm.org/viewvc/llvm-project?rev=276818&view=rev
Log:
Retry: [llvm-cov] Add support for exporting coverage data to JSON

This enables users to export coverage information as portable JSON for use by
analysis tools and storage in document based databases.

The export sub-command is invoked just like the others:

  llvm-cov export -instr-profile path/to/foo.profdata path/to/foo.binary

The resulting JSON contains a list of files and functions. Every file object
contains a list of segments, expansions, and a summary of the file's region,
function, and line coverage. Every function object contains the function's name
and regions. There is also a total summary for the entire object file.

Changes since the initial commit (r276813):

  - Fixed the regexes in the tests to handle Windows filepaths.

Patch by Eddie Hurtig!

Differential Revision: https://reviews.llvm.org/D22651

Added:
    llvm/trunk/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
    llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.json
    llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.json
    llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.json
    llvm/trunk/test/tools/llvm-cov/Inputs/showExpansions.json
    llvm/trunk/test/tools/llvm-cov/Inputs/universal-binary.json
    llvm/trunk/tools/llvm-cov/CoverageExporterJson.cpp
Modified:
    llvm/trunk/docs/CommandGuide/llvm-cov.rst
    llvm/trunk/test/tools/llvm-cov/binary-formats.c
    llvm/trunk/test/tools/llvm-cov/showExpansions.cpp
    llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
    llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
    llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
    llvm/trunk/test/tools/llvm-cov/universal-binary.c
    llvm/trunk/tools/llvm-cov/CMakeLists.txt
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/llvm-cov.cpp

Modified: llvm/trunk/docs/CommandGuide/llvm-cov.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-cov.rst?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-cov.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-cov.rst Tue Jul 26 17:50:58 2016
@@ -24,6 +24,7 @@ COMMANDS
 * :ref:`gcov <llvm-cov-gcov>`
 * :ref:`show <llvm-cov-show>`
 * :ref:`report <llvm-cov-report>`
+* :ref:`export <llvm-cov-export>`
 
 .. program:: llvm-cov gcov
 
@@ -311,6 +312,34 @@ OPTIONS
 
 .. option:: -arch=<name>
 
+ If the covered binary is a universal binary, select the architecture to use.
+ It is an error to specify an architecture that is not included in the
+ universal binary or to use an architecture that does not match a
+ non-universal binary.
+
+EXPORT COMMAND
+--------------
+
+SYNOPSIS
+^^^^^^^^
+
+:program:`llvm-cov export` [*options*] -instr-profile *PROFILE* *BIN*
+
+DESCRIPTION
+^^^^^^^^^^^
+
+The :program:`llvm-cov export` command exports regions, functions, expansions,
+and summaries of the coverage of a binary *BIN* using the profile data
+*PROFILE* as JSON.
+
+For information on compiling programs for coverage and generating profile data,
+see :ref:`llvm-cov-show`.
+
+OPTIONS
+^^^^^^^
+
+.. option:: -arch=<name>
+
  If the covered binary is a universal binary, select the architecture to use.
  It is an error to specify an architecture that is not included in the
  universal binary or to use an architecture that does not match a

Added: llvm/trunk/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/binary-formats.canonical.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/binary-formats.canonical.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/binary-formats.canonical.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,38 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}binary-formats.c",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: [4,40,100,1,1],[4,42,0,0,0]],
+// CHECK-SAME: "expansions":[],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"main","count":100,"regions":[
+// CHECK-SAME: [4,40,4,42,100,0,0,0]
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}binary-formats.c"]
+// CHECK-SAME: }],
+
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,53 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}showHighlightedRanges.cpp",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "expansions":[],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":40,"covered":26,"percent":65,"noncode":0},
+// CHECK-SAME: "functions":{"count":4,"covered":4,"percent":100},
+// CHECK-SAME: "regions":{"count":19,"covered":11,"notcovered":8,"percent":57}}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"_Z4funcv","count":1,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}showHighlightedRanges.cpp"]
+// CHECK-SAME: },
+// CHECK-SAME: {"name":"_Z5func2i","count":1,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}showHighlightedRanges.cpp"]
+// CHECK-SAME: }
+// CHECK-SAME: {"name":"_Z4testv","count":1,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}showHighlightedRanges.cpp"]
+// CHECK-SAME: }
+// CHECK-SAME: {"name":"main","count":1,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{.*}}showHighlightedRanges.cpp"]
+// CHECK-SAME: }],
+
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":40,"covered":26,"percent":65,"noncode":0},
+// CHECK-SAME: "functions":{"count":4,"covered":4,"percent":100},
+// CHECK-SAME: "regions":{"count":19,"covered":11,"notcovered":8,"percent":57}}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,38 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}showLineExecutionCounts.cpp",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "expansions":[],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"main","count":161,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}showLineExecutionCounts.cpp"]
+// CHECK-SAME: }],
+
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":20,"covered":16,"percent":80,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,37 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}showRegionMarkers.cpp",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "expansions":[],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":21,"covered":17,"percent":80,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"main","count":1111000,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":["{{[^"]+}}showRegionMarkers.cpp"]
+// CHECK-SAME: }],
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":21,"covered":17,"percent":80,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":10,"covered":7,"notcovered":3,"percent":70}}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Added: llvm/trunk/test/tools/llvm-cov/Inputs/showExpansions.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/showExpansions.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/showExpansions.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/showExpansions.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,51 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}showExpansions.cpp",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "expansions":[
+// CHECK-SAME: {"source_region":[24,5,24,17,100,0,1,1],
+// CHECK-SAME: "target_regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+
+// Yes, 4 of the same filename in a row
+// CHECK-SAME: "filenames":[
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp","{{[^"]+}}showExpansions.cpp",
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp","{{[^"]+}}showExpansions.cpp"]
+// CHECK-SAME: }],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":17,"covered":15,"percent":88,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":13,"covered":12,"notcovered":1,"percent":92}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"main","count":1,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}
+// CHECK-SAME: ],
+// CHECK-SAME: "filenames":[
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp",
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp",
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp",
+// CHECK-SAME: "{{[^"]+}}showExpansions.cpp"]
+// CHECK-SAME: }],
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":17,"covered":15,"percent":88,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":13,"covered":12,"notcovered":1,"percent":92}}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Added: llvm/trunk/test/tools/llvm-cov/Inputs/universal-binary.json
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/universal-binary.json?rev=276818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/universal-binary.json (added)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/universal-binary.json Tue Jul 26 17:50:58 2016
@@ -0,0 +1,36 @@
+// Metadata section
+// CHECK: {"version":"1.0.0","type":"llvm.coverage.json.export","data":[
+
+// Open Export
+// CHECK-SAME: {"object":"{{[^"]+}}","files":[
+
+// File Object
+// CHECK-SAME: {"filename":"{{[^"]+}}universal-binary.c",
+// CHECK-SAME: "segments":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "expansions":[],
+
+// Verify the Summary Section for the first file
+// CHECK-SAME: "summary":{
+// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}}
+
+// Close Files Array
+// CHECK-SAME: ],
+
+// Functions List
+// CHECK-SAME: "functions":[
+// CHECK-SAME: {"name":"main","count":100,"regions":[
+// CHECK-SAME: {{(\[[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+,[0-9]+\],?)+}}],
+// CHECK-SAME: "filenames":["{{[^"]+}}universal-binary.c"]
+// CHECK-SAME: }],
+
+// Full Export Summary
+// CHECK-SAME: "totals":{
+// CHECK-SAME: "lines":{"count":1,"covered":1,"percent":100,"noncode":0},
+// CHECK-SAME: "functions":{"count":1,"covered":1,"percent":100},
+// CHECK-SAME: "regions":{"count":1,"covered":1,"notcovered":0,"percent":100}
+
+// Close the export object, data array, and root object
+// CHECK-SAME: }]}

Modified: llvm/trunk/test/tools/llvm-cov/binary-formats.c
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/binary-formats.c?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/binary-formats.c (original)
+++ llvm/trunk/test/tools/llvm-cov/binary-formats.c Tue Jul 26 17:50:58 2016
@@ -7,3 +7,7 @@ int main(int argc, const char *argv[]) {
 // RUN: llvm-cov show %S/Inputs/binary-formats.macho32l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s
 // RUN: llvm-cov show %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s
 // RUN: llvm-cov show %S/Inputs/binary-formats.macho32b -instr-profile %t.profdata -filename-equivalence %s | FileCheck %s
+
+// RUN: llvm-cov export %S/Inputs/binary-formats.macho32l -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json
+// RUN: llvm-cov export %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json
+// RUN: llvm-cov export %S/Inputs/binary-formats.macho32b -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json

Modified: llvm/trunk/test/tools/llvm-cov/showExpansions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showExpansions.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showExpansions.cpp (original)
+++ llvm/trunk/test/tools/llvm-cov/showExpansions.cpp Tue Jul 26 17:50:58 2016
@@ -24,3 +24,4 @@ int main(int argc, const char *argv[]) {
     DO_SOMETHING(i); // CHECK-DAG: Expansion at line [[@LINE]], 5 -> 17
   return 0;
 }
+// RUN: llvm-cov export %S/Inputs/showExpansions.covmapping -instr-profile %S/Inputs/showExpansions.profdata 2>&1 | FileCheck %S/Inputs/showExpansions.json

Modified: llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp (original)
+++ llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp Tue Jul 26 17:50:58 2016
@@ -43,3 +43,5 @@ int main() {
   func2(9);
   return 0;
 }
+
+// RUN: llvm-cov export %S/Inputs/highlightedRanges.covmapping -instr-profile %S/Inputs/highlightedRanges.profdata 2>&1 | FileCheck %S/Inputs/highlightedRanges.json

Modified: llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp (original)
+++ llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp Tue Jul 26 17:50:58 2016
@@ -69,3 +69,5 @@ int main() {
 // HTML: <td class='covered-line'><pre>161</pre></td><td class='line-number'><a name='L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='code'><pre>}
 // HTML-WHOLE-FILE: <td class='uncovered-line'></td><td class='line-number'><a name='L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='code'><pre>// after
 // HTML-FILTER-NOT: <td class='uncovered-line'></td><td class='line-number'><a name='L[[@LINE-45]]'><pre>[[@LINE-45]]</pre></a></td><td class='code'><pre>// after
+
+// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -name=main 2>/dev/null | FileCheck %S/Inputs/lineExecutionCounts.json

Modified: llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp (original)
+++ llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp Tue Jul 26 17:50:58 2016
@@ -23,3 +23,5 @@ int main() {                      // CHE
 }
 
 // RUN: llvm-cov show %S/Inputs/regionMarkers.covmapping -instr-profile %t.profdata -show-regions -dump -filename-equivalence %s 2>&1 | FileCheck %s
+
+// RUN: llvm-cov export %S/Inputs/regionMarkers.covmapping -instr-profile %t.profdata 2>&1 | FileCheck %S/Inputs/regionMarkers.json

Modified: llvm/trunk/test/tools/llvm-cov/universal-binary.c
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/universal-binary.c?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/universal-binary.c (original)
+++ llvm/trunk/test/tools/llvm-cov/universal-binary.c Tue Jul 26 17:50:58 2016
@@ -5,6 +5,8 @@ int main(int argc, const char *argv[]) {
 
 // RUN: llvm-profdata merge %S/Inputs/universal-binary.proftext -o %t.profdata
 // RUN: llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -filename-equivalence %s -arch x86_64 | FileCheck %s
+// RUN: llvm-cov export %S/Inputs/universal-binary -instr-profile %t.profdata -arch x86_64 2>&1 | FileCheck %S/Inputs/universal-binary.json
+
 
 // RUN: not llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -filename-equivalence %s -arch i386 2>&1 | FileCheck --check-prefix=WRONG-ARCH %s
 // WRONG-ARCH: Failed to load coverage

Modified: llvm/trunk/tools/llvm-cov/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Tue Jul 26 17:50:58 2016
@@ -4,6 +4,7 @@ add_llvm_tool(llvm-cov
   llvm-cov.cpp
   gcov.cpp
   CodeCoverage.cpp
+  CoverageExporterJson.cpp
   CoverageFilters.cpp
   CoverageReport.cpp
   CoverageSummaryInfo.cpp

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Tue Jul 26 17:50:58 2016
@@ -38,6 +38,10 @@
 using namespace llvm;
 using namespace coverage;
 
+void exportCoverageDataToJson(StringRef ObjectFilename,
+                              const coverage::CoverageMapping &CoverageMapping,
+                              raw_ostream &OS);
+
 namespace {
 /// \brief The implementation of the coverage tool.
 class CodeCoverageTool {
@@ -46,7 +50,9 @@ public:
     /// \brief The show command.
     Show,
     /// \brief The report command.
-    Report
+    Report,
+    /// \brief The export command.
+    Export
   };
 
   /// \brief Print the error message to the error output stream.
@@ -94,6 +100,9 @@ public:
   int report(int argc, const char **argv,
              CommandLineParserType commandLineParser);
 
+  int export_(int argc, const char **argv,
+              CommandLineParserType commandLineParser);
+
   std::string ObjectFilename;
   CoverageViewOptions ViewOpts;
   std::string PGOFilename;
@@ -534,6 +543,8 @@ int CodeCoverageTool::run(Command Cmd, i
     return show(argc, argv, commandLineParser);
   case Report:
     return report(argc, argv, commandLineParser);
+  case Export:
+    return export_(argc, argv, commandLineParser);
   }
   return 0;
 }
@@ -694,6 +705,24 @@ int CodeCoverageTool::report(int argc, c
   return 0;
 }
 
+int CodeCoverageTool::export_(int argc, const char **argv,
+                              CommandLineParserType commandLineParser) {
+
+  auto Err = commandLineParser(argc, argv);
+  if (Err)
+    return Err;
+
+  auto Coverage = load();
+  if (!Coverage) {
+    error("Could not load coverage information");
+    return 1;
+  }
+
+  exportCoverageDataToJson(ObjectFilename, *Coverage.get(), outs());
+
+  return 0;
+}
+
 int showMain(int argc, const char *argv[]) {
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Show, argc, argv);
@@ -703,3 +732,8 @@ int reportMain(int argc, const char *arg
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Report, argc, argv);
 }
+
+int exportMain(int argc, const char *argv[]) {
+  CodeCoverageTool Tool;
+  return Tool.run(CodeCoverageTool::Export, argc, argv);
+}

Added: llvm/trunk/tools/llvm-cov/CoverageExporterJson.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageExporterJson.cpp?rev=276818&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageExporterJson.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageExporterJson.cpp Tue Jul 26 17:50:58 2016
@@ -0,0 +1,418 @@
+//===- CoverageExporterJson.cpp - Code coverage export --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements export of code coverage data to JSON.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//
+// The json code coverage export follows the following format
+// Root: dict => Root Element containing metadata
+// -- Data: array => Homogeneous array of one or more export objects
+// ---- Export: dict => Json representation of one CoverageMapping
+// ------ Files: array => List of objects describing coverage for files
+// -------- File: dict => Coverage for a single file
+// ---------- Segments: array => List of Segments contained in the file
+// ------------ Segment: dict => Describes a segment of the file with a counter
+// ---------- Expansions: array => List of expansion records
+// ------------ Expansion: dict => Object that descibes a single expansion
+// -------------- CountedRegion: dict => The region to be expanded
+// -------------- TargetRegions: array => List of Regions in the expansion
+// ---------------- CountedRegion: dict => Single Region in the expansion
+// ---------- Summary: dict => Object summarizing the coverage for this file
+// ------------ LineCoverage: dict => Object summarizing line coverage
+// ------------ FunctionCoverage: dict => Object summarizing function coverage
+// ------------ RegionCoverage: dict => Object summarizing region coverage
+// ------ Functions: array => List of objects describing coverage for functions
+// -------- Function: dict => Coverage info for a single function
+// ---------- Filenames: array => List of filenames that the function relates to
+// ---- Summary: dict => Object summarizing the coverage for the entire binary
+// ------ LineCoverage: dict => Object summarizing line coverage
+// ------ FunctionCoverage: dict => Object summarizing function coverage
+// ------ RegionCoverage: dict => Object summarizing region coverage
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageSummaryInfo.h"
+#include "CoverageViewOptions.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include <stack>
+
+/// \brief Major version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_MAJOR 1
+
+/// \brief Minor version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_MINOR 0
+
+/// \brief Patch version of the JSON Coverage Export Format.
+#define LLVM_COVERAGE_EXPORT_JSON_PATCH 0
+
+/// \brief The semantic version combined as a string.
+#define LLVM_COVERAGE_EXPORT_JSON_STR "1.0.0"
+
+/// \brief Unique type identifier for JSON coverage export.
+#define LLVM_COVERAGE_EXPORT_JSON_TYPE_STR "llvm.coverage.json.export"
+
+using namespace llvm;
+using namespace coverage;
+
+class CoverageExporterJson {
+  /// \brief A Name of the object file coverage is for.
+  StringRef ObjectFilename;
+
+  /// \brief Output stream to print JSON to.
+  raw_ostream &OS;
+
+  /// \brief The full CoverageMapping object to export.
+  CoverageMapping Coverage;
+
+  /// \brief States that the JSON rendering machine can be in.
+  enum JsonState { None, NonEmptyElement, EmptyElement };
+
+  /// \brief Tracks state of the JSON output.
+  std::stack<JsonState> State;
+
+  /// \brief Get the object filename.
+  StringRef getObjectFilename() const { return ObjectFilename; }
+
+  /// \brief Emit a serialized scalar.
+  void emitSerialized(const int64_t Value) { OS << Value; }
+
+  /// \brief Emit a serialized string.
+  void emitSerialized(const std::string &Value) { OS << "\"" << Value << "\""; }
+
+  /// \brief Emit a comma if there is a previous element to delimit.
+  void emitComma() {
+    if (State.top() == JsonState::NonEmptyElement) {
+      OS << ",";
+    } else if (State.top() == JsonState::EmptyElement) {
+      State.pop();
+      assert((State.size() >= 1) && "Closed too many JSON elements");
+      State.push(JsonState::NonEmptyElement);
+    }
+  }
+
+  /// \brief Emit a starting dictionary/object character.
+  void emitDictStart() {
+    emitComma();
+    State.push(JsonState::EmptyElement);
+    OS << "{";
+  }
+
+  /// \brief Emit a dictionary/object key but no value.
+  void emitDictKey(const std::string &Key) {
+    emitComma();
+    OS << "\"" << Key << "\":";
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+
+    // We do not want to emit a comma after this key.
+    State.push(JsonState::EmptyElement);
+  }
+
+  /// \brief Emit a dictionary/object key/value pair.
+  template <typename V>
+  void emitDictElement(const std::string &Key, const V &Value) {
+    emitComma();
+    emitSerialized(Key);
+    OS << ":";
+    emitSerialized(Value);
+  }
+
+  /// \brief Emit a closing dictionary/object character.
+  void emitDictEnd() {
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+    OS << "}";
+  }
+
+  /// \brief Emit a starting array character.
+  void emitArrayStart() {
+    emitComma();
+    State.push(JsonState::EmptyElement);
+    OS << "[";
+  }
+
+  /// \brief Emit an array element.
+  template <typename V> void emitArrayElement(const V &Value) {
+    emitComma();
+    emitSerialized(Value);
+  }
+
+  /// \brief emit a closing array character.
+  void emitArrayEnd() {
+    State.pop();
+    assert((State.size() >= 1) && "Closed too many JSON elements");
+    OS << "]";
+  }
+
+  /// \brief Render the CoverageMapping object.
+  void renderRoot() {
+    // Start Root of JSON object.
+    emitDictStart();
+
+    emitDictElement("version", LLVM_COVERAGE_EXPORT_JSON_STR);
+    emitDictElement("type", LLVM_COVERAGE_EXPORT_JSON_TYPE_STR);
+    emitDictKey("data");
+
+    // Start List of Exports.
+    emitArrayStart();
+
+    // Start Export.
+    emitDictStart();
+    emitDictElement("object", getObjectFilename());
+
+    emitDictKey("files");
+    FileCoverageSummary Totals = FileCoverageSummary("Totals");
+    renderFiles(Coverage.getUniqueSourceFiles(), Totals);
+
+    emitDictKey("functions");
+    renderFunctions(Coverage.getCoveredFunctions());
+
+    emitDictKey("totals");
+    renderSummary(Totals);
+
+    // End Export.
+    emitDictEnd();
+
+    // End List of Exports.
+    emitArrayEnd();
+
+    // End Root of JSON Object.
+    emitDictEnd();
+
+    assert((State.top() == JsonState::None) &&
+           "All Elements In JSON were Closed");
+  }
+
+  /// \brief Render an array of all the given functions.
+  void
+  renderFunctions(const iterator_range<FunctionRecordIterator> &Functions) {
+    // Start List of Functions.
+    emitArrayStart();
+
+    for (const auto &Function : Functions) {
+      // Start Function.
+      emitDictStart();
+
+      emitDictElement("name", Function.Name);
+      emitDictElement("count", Function.ExecutionCount);
+      emitDictKey("regions");
+
+      renderRegions(Function.CountedRegions);
+
+      emitDictKey("filenames");
+
+      // Start Filenames for Function.
+      emitArrayStart();
+
+      for (const auto &FileName : Function.Filenames)
+        emitArrayElement(FileName);
+
+      // End Filenames for Function.
+      emitArrayEnd();
+
+      // End Function.
+      emitDictEnd();
+    }
+
+    // End List of Functions.
+    emitArrayEnd();
+  }
+
+  /// \brief Render an array of all the source files, also pass back a Summary.
+  void renderFiles(ArrayRef<StringRef> SourceFiles,
+                   FileCoverageSummary &Summary) {
+    // Start List of Files.
+    emitArrayStart();
+    for (const auto &SourceFile : SourceFiles) {
+      // Render the file.
+      auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+      renderFile(FileCoverage);
+
+      for (const auto &F : Coverage.getCoveredFunctions(SourceFile))
+        Summary.addFunction(FunctionCoverageSummary::get(F));
+    }
+
+    // End List of Files.
+    emitArrayEnd();
+  }
+
+  /// \brief Render a single file.
+  void renderFile(const CoverageData &FileCoverage) {
+    // Start File.
+    emitDictStart();
+
+    emitDictElement("filename", FileCoverage.getFilename());
+    emitDictKey("segments");
+
+    // Start List of Segments.
+    emitArrayStart();
+
+    for (const auto &Segment : FileCoverage)
+      renderSegment(Segment);
+
+    // End List of Segments.
+    emitArrayEnd();
+
+    emitDictKey("expansions");
+
+    // Start List of Expansions.
+    emitArrayStart();
+
+    for (const auto &Expansion : FileCoverage.getExpansions())
+      renderExpansion(Expansion);
+
+    // End List of Expansions.
+    emitArrayEnd();
+
+    FileCoverageSummary Summary =
+        FileCoverageSummary(FileCoverage.getFilename());
+    for (const auto &F :
+         Coverage.getCoveredFunctions(FileCoverage.getFilename()))
+      Summary.addFunction(FunctionCoverageSummary::get(F));
+
+    emitDictKey("summary");
+    renderSummary(Summary);
+
+    // End File.
+    emitDictEnd();
+  }
+
+  /// \brief Render a CoverageSegment.
+  void renderSegment(const CoverageSegment &Segment) {
+    // Start Segment.
+    emitArrayStart();
+
+    emitArrayElement(Segment.Line);
+    emitArrayElement(Segment.Col);
+    emitArrayElement(Segment.Count);
+    emitArrayElement(Segment.HasCount);
+    emitArrayElement(Segment.IsRegionEntry);
+
+    // End Segment.
+    emitArrayEnd();
+  }
+
+  /// \brief Render an ExpansionRecord.
+  void renderExpansion(const ExpansionRecord &Expansion) {
+    // Start Expansion.
+    emitDictStart();
+
+    // Mark the beginning and end of this expansion in the source file.
+    emitDictKey("source_region");
+    renderRegion(Expansion.Region);
+
+    // Enumerate the coverage information for the expansion.
+    emitDictKey("target_regions");
+    renderRegions(Expansion.Function.CountedRegions);
+
+    emitDictKey("filenames");
+    // Start List of Filenames to map the fileIDs.
+    emitArrayStart();
+    for (const auto &Filename : Expansion.Function.Filenames)
+      emitArrayElement(Filename);
+    // End List of Filenames.
+    emitArrayEnd();
+
+    // End Expansion.
+    emitDictEnd();
+  }
+
+  /// \brief Render a list of CountedRegions.
+  void renderRegions(ArrayRef<CountedRegion> Regions) {
+    // Start List of Regions.
+    emitArrayStart();
+
+    for (const auto &Region : Regions)
+      renderRegion(Region);
+
+    // End List of Regions.
+    emitArrayEnd();
+  }
+
+  /// \brief Render a single CountedRegion.
+  void renderRegion(const CountedRegion &Region) {
+    // Start CountedRegion.
+    emitArrayStart();
+
+    emitArrayElement(Region.LineStart);
+    emitArrayElement(Region.ColumnStart);
+    emitArrayElement(Region.LineEnd);
+    emitArrayElement(Region.ColumnEnd);
+    emitArrayElement(Region.ExecutionCount);
+    emitArrayElement(Region.FileID);
+    emitArrayElement(Region.ExpandedFileID);
+    emitArrayElement(Region.Kind);
+
+    // End CountedRegion.
+    emitArrayEnd();
+  }
+
+  /// \brief Render a FileCoverageSummary.
+  void renderSummary(const FileCoverageSummary &Summary) {
+    // Start Summary for the file.
+    emitDictStart();
+
+    emitDictKey("lines");
+
+    // Start Line Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.LineCoverage.NumLines);
+    emitDictElement("covered", Summary.LineCoverage.Covered);
+    emitDictElement("percent", Summary.LineCoverage.getPercentCovered());
+    emitDictElement("noncode", Summary.LineCoverage.NonCodeLines);
+    // End Line Coverage Summary.
+    emitDictEnd();
+
+    emitDictKey("functions");
+
+    // Start Function Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.FunctionCoverage.NumFunctions);
+    emitDictElement("covered", Summary.FunctionCoverage.Executed);
+    emitDictElement("percent", Summary.FunctionCoverage.getPercentCovered());
+    // End Function Coverage Summary.
+    emitDictEnd();
+
+    emitDictKey("regions");
+
+    // Start Region Coverage Summary.
+    emitDictStart();
+    emitDictElement("count", Summary.RegionCoverage.NumRegions);
+    emitDictElement("covered", Summary.RegionCoverage.Covered);
+    emitDictElement("notcovered", Summary.RegionCoverage.NotCovered);
+    emitDictElement("percent", Summary.RegionCoverage.getPercentCovered());
+    // End Region Coverage Summary.
+    emitDictEnd();
+
+    // End Summary for the file.
+    emitDictEnd();
+  }
+
+public:
+  CoverageExporterJson(StringRef ObjectFilename,
+                       const CoverageMapping &CoverageMapping, raw_ostream &OS)
+      : ObjectFilename(ObjectFilename), OS(OS), Coverage(CoverageMapping) {
+    State.push(JsonState::None);
+  }
+
+  /// \brief Print the CoverageMapping.
+  void print() { renderRoot(); }
+};
+
+/// \brief Export the given CoverageMapping to a JSON Format.
+void exportCoverageDataToJson(StringRef ObjectFilename,
+                              const CoverageMapping &CoverageMapping,
+                              raw_ostream &OS) {
+  auto Exporter = CoverageExporterJson(ObjectFilename, CoverageMapping, OS);
+
+  Exporter.print();
+}

Modified: llvm/trunk/tools/llvm-cov/llvm-cov.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/llvm-cov.cpp?rev=276818&r1=276817&r2=276818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/llvm-cov.cpp (original)
+++ llvm/trunk/tools/llvm-cov/llvm-cov.cpp Tue Jul 26 17:50:58 2016
@@ -30,6 +30,9 @@ int showMain(int argc, const char *argv[
 /// \brief The main entry point for the 'report' subcommand.
 int reportMain(int argc, const char *argv[]);
 
+/// \brief The main entry point for the 'export' subcommand.
+int exportMain(int argc, const char *argv[]);
+
 /// \brief The main entry point for the 'convert-for-testing' subcommand.
 int convertForTestingMain(int argc, const char *argv[]);
 
@@ -38,12 +41,14 @@ int gcovMain(int argc, const char *argv[
 
 /// \brief Top level help.
 static int helpMain(int argc, const char *argv[]) {
-  errs() << "Usage: llvm-cov {gcov|report|show} [OPTION]...\n\n"
+  errs() << "Usage: llvm-cov {export|gcov|report|show} [OPTION]...\n\n"
          << "Shows code coverage information.\n\n"
          << "Subcommands:\n"
+         << "  export: Export instrprof file to structured format.\n"
          << "  gcov:   Work with the gcov format.\n"
-         << "  show:   Annotate source files using instrprof style coverage.\n"
-         << "  report: Summarize instrprof style coverage information.\n";
+         << "  report: Summarize instrprof style coverage information.\n"
+         << "  show:   Annotate source files using instrprof style coverage.\n";
+
   return 0;
 }
 
@@ -68,6 +73,7 @@ int main(int argc, const char **argv) {
     typedef int (*MainFunction)(int, const char *[]);
     MainFunction Func = StringSwitch<MainFunction>(argv[1])
                             .Case("convert-for-testing", convertForTestingMain)
+                            .Case("export", exportMain)
                             .Case("gcov", gcovMain)
                             .Case("report", reportMain)
                             .Case("show", showMain)




More information about the llvm-commits mailing list