Skip to content

Commit

Permalink
[llvm-cov] Add support for exporting coverage data to JSON
Browse files Browse the repository at this point in the history
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.

Patch by Eddie Hurtig!

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

llvm-svn: 276813
  • Loading branch information
vedantk committed Jul 26, 2016
1 parent 219ab36 commit d5b7436
Show file tree
Hide file tree
Showing 17 changed files with 759 additions and 4 deletions.
29 changes: 29 additions & 0 deletions llvm/docs/CommandGuide/llvm-cov.rst
Expand Up @@ -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

Expand Down Expand Up @@ -315,3 +316,31 @@ OPTIONS
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
non-universal binary.
38 changes: 38 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/binary-formats.canonical.json
@@ -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: }]}
53 changes: 53 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/highlightedRanges.json
@@ -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: }]}
38 changes: 38 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/lineExecutionCounts.json
@@ -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: }]}
37 changes: 37 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/regionMarkers.json
@@ -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: }]}
51 changes: 51 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/showExpansions.json
@@ -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: }]}
36 changes: 36 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/universal-binary.json
@@ -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: }]}
4 changes: 4 additions & 0 deletions llvm/test/tools/llvm-cov/binary-formats.c
Expand Up @@ -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
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-cov/showExpansions.cpp
Expand Up @@ -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
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-cov/showHighlightedRanges.cpp
Expand Up @@ -43,3 +43,4 @@ 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
4 changes: 4 additions & 0 deletions llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
Expand Up @@ -69,3 +69,7 @@ int main() { // TEXT: 161| [[@LINE]]|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 > %t.json
// FileCheck -input-file=%t.json %S/Inputs/lineExecutionCounts.json
// RUN: cat %t.json | %python -c 'import json, sys; json.loads(sys.stdin.read())'
2 changes: 2 additions & 0 deletions llvm/test/tools/llvm-cov/showRegionMarkers.cpp
Expand Up @@ -23,3 +23,5 @@ int main() { // CHECK: Marker at [[@LINE]]:12 = 1.11M
}

// 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
2 changes: 2 additions & 0 deletions llvm/test/tools/llvm-cov/universal-binary.c
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/tools/llvm-cov/CMakeLists.txt
Expand Up @@ -4,6 +4,7 @@ add_llvm_tool(llvm-cov
llvm-cov.cpp
gcov.cpp
CodeCoverage.cpp
CoverageExporterJson.cpp
CoverageFilters.cpp
CoverageReport.cpp
CoverageSummaryInfo.cpp
Expand Down

0 comments on commit d5b7436

Please sign in to comment.