• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2019 The TensorFlow Authors. 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 "tensorflow/core/profiler/utils/parse_annotation.h"
16 
17 #include <stack>
18 #include <string>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/strings/ascii.h"
23 #include "absl/strings/str_split.h"
24 #include "absl/strings/string_view.h"
25 
26 namespace tensorflow {
27 namespace profiler {
28 namespace {
29 
SplitNameAndMetadata(absl::string_view annotation)30 std::vector<absl::string_view> SplitNameAndMetadata(
31     absl::string_view annotation) {
32   std::vector<absl::string_view> parts;
33   if (!HasMetadata(annotation)) {
34     parts.emplace_back(annotation);
35   } else {
36     annotation.remove_suffix(1);
37     parts = absl::StrSplit(annotation, '#');
38     if (parts.size() > 2) {
39       parts.resize(2);
40     }
41   }
42   while (parts.size() < 2) {
43     parts.emplace_back();
44   }
45   return parts;
46 }
47 
48 // Use comma as separate to split input metadata. However, treat comma inside
49 // ""/''/[]/{}/() pairs as normal characters.
SplitPairs(absl::string_view metadata)50 std::vector<absl::string_view> SplitPairs(absl::string_view metadata) {
51   std::vector<absl::string_view> key_value_pairs;
52   std::stack<char> quotes;
53   size_t start = 0, end = 0;
54   for (; end < metadata.size(); ++end) {
55     char ch = metadata[end];
56     switch (ch) {
57       case '\"':
58       case '\'':
59         if (quotes.empty() || quotes.top() != ch) {
60           quotes.push(ch);
61         } else {
62           quotes.pop();
63         }
64         break;
65       case '{':
66       case '(':
67       case '[':
68         quotes.push(ch);
69         break;
70       case '}':
71         if (!quotes.empty() && quotes.top() == '{') {
72           quotes.pop();
73         }
74         break;
75       case ')':
76         if (!quotes.empty() && quotes.top() == '(') {
77           quotes.pop();
78         }
79         break;
80       case ']':
81         if (!quotes.empty() && quotes.top() == '[') {
82           quotes.pop();
83         }
84         break;
85       case ',':
86         if (quotes.empty()) {
87           if (end - start > 1) {
88             key_value_pairs.emplace_back(metadata.data() + start, end - start);
89           }
90           start = end + 1;  // Skip the current ','.
91         }
92         break;
93     }
94   }
95   if (end - start > 1) {
96     key_value_pairs.emplace_back(metadata.data() + start, end - start);
97   }
98   return key_value_pairs;
99 }
100 
ParseMetadata(absl::string_view metadata)101 std::vector<std::pair<absl::string_view, absl::string_view>> ParseMetadata(
102     absl::string_view metadata) {
103   std::vector<std::pair<absl::string_view, absl::string_view>> key_values;
104   for (absl::string_view pair : SplitPairs(metadata)) {
105     std::vector<absl::string_view> parts =
106         absl::StrSplit(pair, absl::MaxSplits('=', 1));
107     if (parts.size() == 2) {
108       absl::string_view key = absl::StripAsciiWhitespace(parts[0]);
109       absl::string_view value = absl::StripAsciiWhitespace(parts[1]);
110       if (!key.empty() && !value.empty()) {
111         key_values.push_back({key, value});
112       }
113     }
114   }
115   return key_values;
116 }
117 
118 }  // namespace
119 
ParseAnnotation(absl::string_view annotation)120 Annotation ParseAnnotation(absl::string_view annotation) {
121   Annotation result;
122   std::vector<absl::string_view> parts = SplitNameAndMetadata(annotation);
123   if (!parts.empty()) {
124     result.name = absl::StripAsciiWhitespace(parts[0]);
125     for (const auto& key_value : ParseMetadata(parts[1])) {
126       result.metadata.push_back({key_value.first, key_value.second});
127     }
128   }
129   return result;
130 }
131 
ParseAnnotationStack(absl::string_view annotation_stack)132 std::vector<Annotation> ParseAnnotationStack(
133     absl::string_view annotation_stack) {
134   std::vector<Annotation> annotations;
135   const std::string kAnnotationDelimiter = "::";
136   for (absl::string_view annotation : absl::StrSplit(
137            annotation_stack, kAnnotationDelimiter, absl::SkipEmpty())) {
138     annotations.emplace_back(ParseAnnotation(annotation));
139   }
140   return annotations;
141 }
142 
143 }  // namespace profiler
144 }  // namespace tensorflow
145