1 : // Copyright 2012 Google Inc. 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 : #include "syzygy/grinder/cache_grind_writer.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "base/strings/string_util.h"
19 :
20 : namespace grinder {
21 :
22 : bool WriteCacheGrindCoverageFile(const CoverageData& coverage,
23 E : const base::FilePath& path) {
24 E : base::ScopedFILE file(base::OpenFile(path, "wb"));
25 E : if (file.get() == NULL) {
26 i : LOG(ERROR) << "Failed to open file for writing: " << path.value();
27 i : return false;
28 : }
29 :
30 E : if (!WriteCacheGrindCoverageFile(coverage, file.get())) {
31 i : LOG(ERROR) << "Failed to write CacheGrind file: " << path.value();
32 i : return false;
33 : }
34 :
35 E : return true;
36 E : }
37 :
38 E : bool WriteCacheGrindCoverageFile(const CoverageData& coverage, FILE* file) {
39 E : DCHECK(file != NULL);
40 :
41 : // Output the position and event types.
42 E : if (::fprintf(file, "positions: line\n") < 0)
43 i : return false;
44 E : if (::fprintf(file, "events: Instrumented Executed\n") < 0)
45 i : return false;
46 :
47 : // Iterate over the source files.
48 : CoverageData::SourceFileCoverageDataMap::const_iterator source_it =
49 E : coverage.source_file_coverage_data_map().begin();
50 : CoverageData::SourceFileCoverageDataMap::const_iterator source_it_end =
51 E : coverage.source_file_coverage_data_map().end();
52 E : for (; source_it != source_it_end; ++source_it) {
53 : // Output the path, being sure to use forward slashes instead of
54 : // back slashes.
55 E : std::string path = source_it->first;
56 E : if (!base::ReplaceChars(path, "\\", "/", &path))
57 i : return false;
58 E : if (::fprintf(file, "fl=%s\n", path.c_str()) < 0)
59 i : return false;
60 :
61 : // We need to output a dummy function name for cache-grind aggregation to
62 : // work appropriately.
63 E : if (::fprintf(file, "fn=all\n") < 0)
64 i : return false;
65 :
66 : // Iterate over the instrumented lines. We output deltas to save space so
67 : // keep track of the previous line. Lines are 1 indexed so we can use zero
68 : // as a special value.
69 E : size_t prev_line = 0;
70 : CoverageData::LineExecutionCountMap::const_iterator line_it =
71 E : source_it->second.line_execution_count_map.begin();
72 : CoverageData::LineExecutionCountMap::const_iterator line_it_end =
73 E : source_it->second.line_execution_count_map.end();
74 E : for (; line_it != line_it_end; ++line_it) {
75 E : if (prev_line == 0) {
76 : // Output the raw line number.
77 E : if (::fprintf(file, "%d 1 %d\n", line_it->first, line_it->second) < 0)
78 i : return false;
79 E : } else {
80 : // Output the line number as a delta from the previous line number.
81 E : DCHECK_LT(prev_line, line_it->first);
82 : if (::fprintf(file, "+%d 1 %d\n", line_it->first - prev_line,
83 E : line_it->second) < 0) {
84 i : return false;
85 : }
86 : }
87 E : prev_line = line_it->first;
88 E : }
89 E : }
90 :
91 E : return true;
92 E : }
93 :
94 : } // namespace grinder
|