1 // Copyright 2015 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "perf_stat_parser.h"
6 
7 #include <stdlib.h>  // for strtoull and strtod
8 
9 #include <vector>
10 
11 #include "base/logging.h"
12 
13 #include "compat/proto.h"
14 #include "file_utils.h"
15 #include "string_utils.h"
16 
17 namespace quipper {
18 
ParsePerfStatFileToProto(const string & path,PerfStatProto * proto)19 bool ParsePerfStatFileToProto(const string& path, PerfStatProto* proto) {
20   std::vector<char> data;
21   if (!FileToBuffer(path, &data)) {
22     return false;
23   }
24   string data_str(data.begin(), data.end());
25   return ParsePerfStatOutputToProto(data_str, proto);
26 }
27 
ParsePerfStatOutputToProto(const string & data,PerfStatProto * proto)28 bool ParsePerfStatOutputToProto(const string& data, PerfStatProto* proto) {
29   std::vector<string> lines;
30   SplitString(data, '\n', &lines);
31   uint64_t time_ms = 0;
32   for (size_t i = 0; i < lines.size(); ++i) {
33     TrimWhitespace(&lines[i]);
34     // Look for lines of the form:
35     // "name: 123 123 123"
36     // OR
37     // "1.234 seconds time elapsed"
38     std::vector<string> tokens;
39     SplitString(lines[i], ' ', &tokens);
40     if (tokens.size() != 4) {
41       continue;
42     }
43     const string& first_token = tokens[0];
44     // Look for "name: 123 123 123"
45     if (first_token.back() == ':') {
46       char* endptr;
47       uint64_t count = strtoull(tokens[1].c_str(), &endptr, 10);
48       if (*endptr != '\0') {
49         continue;
50       }
51       auto newline = proto->add_line();
52       newline->set_count(count);
53       newline->set_event_name(first_token.substr(0, first_token.size() - 1));
54     }
55     // Look for "1.234 seconds time elapsed"
56     if (tokens[1] == "seconds" &&
57         !SecondsStringToMillisecondsUint64(first_token, &time_ms)) {
58       time_ms = 0;
59     }
60   }
61   if (time_ms != 0) {
62     for (int i = 0; i < proto->line_size(); ++i) {
63       proto->mutable_line(i)->set_time_ms(time_ms);
64     }
65   }
66   return proto->line_size() > 0;
67 }
68 
SecondsStringToMillisecondsUint64(const string & str,uint64_t * out)69 bool SecondsStringToMillisecondsUint64(const string& str, uint64_t* out) {
70   char* endptr;
71   double seconds = strtod(str.c_str(), &endptr);
72   if (*endptr != '\0') {
73     return false;
74   }
75   if (seconds < 0) {
76     return false;
77   }
78   *out = (static_cast<uint64_t>(seconds * 1000.0 + 0.5));
79   return true;
80 }
81 
82 }  // namespace quipper
83