Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/logging/logSelection.cpp
40930 views
1
/*
2
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
#include "precompiled.hpp"
25
#include "jvm_io.h"
26
#include "utilities/ostream.hpp"
27
#include "logging/log.hpp"
28
#include "logging/logSelection.hpp"
29
#include "logging/logTagSet.hpp"
30
#include "runtime/os.hpp"
31
#include "utilities/globalDefinitions.hpp"
32
#include "utilities/ostream.hpp"
33
#include "utilities/quickSort.hpp"
34
35
const LogSelection LogSelection::Invalid;
36
37
LogSelection::LogSelection() : _ntags(0), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) {
38
}
39
40
LogSelection::LogSelection(const LogTagType tags[LogTag::MaxTags], bool wildcard, LogLevelType level)
41
: _ntags(0), _wildcard(wildcard), _level(level), _tag_sets_selected(0) {
42
while (_ntags < LogTag::MaxTags && tags[_ntags] != LogTag::__NO_TAG) {
43
_tags[_ntags] = tags[_ntags];
44
_ntags++;
45
}
46
47
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
48
if (selects(*ts)) {
49
_tag_sets_selected++;
50
}
51
}
52
}
53
54
bool LogSelection::operator==(const LogSelection& ref) const {
55
if (_ntags != ref._ntags ||
56
_wildcard != ref._wildcard ||
57
_level != ref._level ||
58
_tag_sets_selected != ref._tag_sets_selected) {
59
return false;
60
}
61
for (size_t i = 0; i < _ntags; i++) {
62
if (_tags[i] != ref._tags[i]) {
63
return false;
64
}
65
}
66
return true;
67
}
68
69
bool LogSelection::operator!=(const LogSelection& ref) const {
70
return !operator==(ref);
71
}
72
73
static LogSelection parse_internal(char *str, outputStream* errstream) {
74
// Parse the level, if specified
75
LogLevelType level = LogLevel::Unspecified;
76
char* equals = strchr(str, '=');
77
if (equals != NULL) {
78
const char* levelstr = equals + 1;
79
level = LogLevel::from_string(levelstr);
80
if (level == LogLevel::Invalid) {
81
if (errstream != NULL) {
82
errstream->print("Invalid level '%s' in log selection.", levelstr);
83
LogLevelType match = LogLevel::fuzzy_match(levelstr);
84
if (match != LogLevel::Invalid) {
85
errstream->print(" Did you mean '%s'?", LogLevel::name(match));
86
}
87
errstream->cr();
88
}
89
return LogSelection::Invalid;
90
}
91
*equals = '\0';
92
}
93
94
size_t ntags = 0;
95
LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG };
96
97
// Parse special tags such as 'all'
98
if (strcmp(str, "all") == 0) {
99
return LogSelection(tags, true, level);
100
}
101
102
// Check for '*' suffix
103
bool wildcard = false;
104
char* asterisk_pos = strchr(str, '*');
105
if (asterisk_pos != NULL && asterisk_pos[1] == '\0') {
106
wildcard = true;
107
*asterisk_pos = '\0';
108
}
109
110
// Parse the tag expression (t1+t2+...+tn)
111
char* plus_pos;
112
char* cur_tag = str;
113
do {
114
plus_pos = strchr(cur_tag, '+');
115
if (plus_pos != NULL) {
116
*plus_pos = '\0';
117
}
118
LogTagType tag = LogTag::from_string(cur_tag);
119
if (tag == LogTag::__NO_TAG) {
120
if (errstream != NULL) {
121
errstream->print("Invalid tag '%s' in log selection.", cur_tag);
122
LogTagType match = LogTag::fuzzy_match(cur_tag);
123
if (match != LogTag::__NO_TAG) {
124
errstream->print(" Did you mean '%s'?", LogTag::name(match));
125
}
126
errstream->cr();
127
}
128
return LogSelection::Invalid;
129
}
130
if (ntags == LogTag::MaxTags) {
131
if (errstream != NULL) {
132
errstream->print_cr("Too many tags in log selection '%s' (can only have up to " SIZE_FORMAT " tags).",
133
str, LogTag::MaxTags);
134
}
135
return LogSelection::Invalid;
136
}
137
tags[ntags++] = tag;
138
cur_tag = plus_pos + 1;
139
} while (plus_pos != NULL);
140
141
for (size_t i = 0; i < ntags; i++) {
142
for (size_t j = 0; j < ntags; j++) {
143
if (i != j && tags[i] == tags[j]) {
144
if (errstream != NULL) {
145
errstream->print_cr("Log selection contains duplicates of tag %s.", LogTag::name(tags[i]));
146
}
147
return LogSelection::Invalid;
148
}
149
}
150
}
151
152
return LogSelection(tags, wildcard, level);
153
}
154
155
LogSelection LogSelection::parse(const char* str, outputStream* error_stream) {
156
char* copy = os::strdup_check_oom(str, mtLogging);
157
LogSelection s = parse_internal(copy, error_stream);
158
os::free(copy);
159
return s;
160
}
161
162
bool LogSelection::selects(const LogTagSet& ts) const {
163
if (!_wildcard && _ntags != ts.ntags()) {
164
return false;
165
}
166
for (size_t i = 0; i < _ntags; i++) {
167
if (!ts.contains(_tags[i])) {
168
return false;
169
}
170
}
171
return true;
172
}
173
174
static bool contains(LogTagType tag, const LogTagType tags[LogTag::MaxTags], size_t ntags) {
175
for (size_t i = 0; i < ntags; i++) {
176
if (tags[i] == tag) {
177
return true;
178
}
179
}
180
return false;
181
}
182
183
bool LogSelection::consists_of(const LogTagType tags[LogTag::MaxTags]) const {
184
size_t i;
185
for (i = 0; tags[i] != LogTag::__NO_TAG; i++) {
186
if (!contains(tags[i], _tags, _ntags)) {
187
return false;
188
}
189
}
190
return i == _ntags;
191
}
192
193
size_t LogSelection::ntags() const {
194
return _ntags;
195
}
196
197
LogLevelType LogSelection::level() const {
198
return _level;
199
}
200
201
size_t LogSelection::tag_sets_selected() const {
202
return _tag_sets_selected;
203
}
204
205
int LogSelection::describe_tags(char* buf, size_t bufsize) const {
206
int tot_written = 0;
207
for (size_t i = 0; i < _ntags; i++) {
208
int written = jio_snprintf(buf + tot_written, bufsize - tot_written,
209
"%s%s", (i == 0 ? "" : "+"), LogTag::name(_tags[i]));
210
if (written == -1) {
211
return written;
212
}
213
tot_written += written;
214
}
215
216
if (_wildcard) {
217
int written = jio_snprintf(buf + tot_written, bufsize - tot_written, "*");
218
if (written == -1) {
219
return written;
220
}
221
tot_written += written;
222
}
223
return tot_written;
224
}
225
226
int LogSelection::describe(char* buf, size_t bufsize) const {
227
int tot_written = describe_tags(buf, bufsize);
228
229
int written = jio_snprintf(buf + tot_written, bufsize - tot_written, "=%s", LogLevel::name(_level));
230
if (written == -1) {
231
return -1;
232
}
233
tot_written += written;
234
return tot_written;
235
}
236
237
double LogSelection::similarity(const LogSelection& other) const {
238
// Compute Soerensen-Dice coefficient as the similarity measure
239
size_t intersecting = 0;
240
for (size_t i = 0; i < _ntags; i++) {
241
for (size_t j = 0; j < other._ntags; j++) {
242
if (_tags[i] == other._tags[j]) {
243
intersecting++;
244
break;
245
}
246
}
247
}
248
return 2.0 * intersecting / (_ntags + other._ntags);
249
}
250
251
// Comparator used for sorting LogSelections based on their similarity to a specific LogSelection.
252
// A negative return value means that 'a' is more similar to 'ref' than 'b' is, while a positive
253
// return value means that 'b' is more similar.
254
// For the sake of giving short and effective suggestions, when two selections have an equal
255
// similarity score, the selection with the fewer tags (selecting the most tag sets) is considered
256
// more similar.
257
class SimilarityComparator {
258
const LogSelection& _ref;
259
public:
260
SimilarityComparator(const LogSelection& ref) : _ref(ref) {
261
}
262
int operator()(const LogSelection& a, const LogSelection& b) const {
263
const double epsilon = 1.0e-6;
264
265
// Sort by similarity (descending)
266
double s = _ref.similarity(b) - _ref.similarity(a);
267
if (fabs(s) > epsilon) {
268
return s < 0 ? -1 : 1;
269
}
270
271
// Then by number of tags (ascending)
272
int t = static_cast<int>(a.ntags() - (int)b.ntags());
273
if (t != 0) {
274
return t;
275
}
276
277
// Lastly by tag sets selected (descending)
278
return static_cast<int>(b.tag_sets_selected() - a.tag_sets_selected());
279
}
280
};
281
282
static const size_t suggestion_cap = 5;
283
static const double similarity_requirement = 0.3;
284
void LogSelection::suggest_similar_matching(outputStream* out) const {
285
LogSelection suggestions[suggestion_cap];
286
uint nsuggestions = 0;
287
288
// See if simply adding a wildcard would make the selection match
289
if (!_wildcard) {
290
LogSelection sel(_tags, true, _level);
291
if (sel.tag_sets_selected() > 0) {
292
suggestions[nsuggestions++] = sel;
293
}
294
}
295
296
// Check for matching tag sets with a single tag mismatching (a tag too many or short a tag)
297
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
298
LogTagType tags[LogTag::MaxTags] = { LogTag::__NO_TAG };
299
for (size_t i = 0; i < ts->ntags(); i++) {
300
tags[i] = ts->tag(i);
301
}
302
303
// Suggest wildcard selection unless the wildcard doesn't match anything extra
304
LogSelection sel(tags, true, _level);
305
if (sel.tag_sets_selected() == 1) {
306
sel = LogSelection(tags, false, _level);
307
}
308
309
double score = similarity(sel);
310
311
// Ignore suggestions with too low similarity
312
if (score < similarity_requirement) {
313
continue;
314
}
315
316
// Cap not reached, simply add the new suggestion and continue searching
317
if (nsuggestions < suggestion_cap) {
318
suggestions[nsuggestions++] = sel;
319
continue;
320
}
321
322
// Find the least matching suggestion already found, and if the new suggestion is a better match, replace it
323
double min = 1.0;
324
size_t pos = -1;
325
for (size_t i = 0; i < nsuggestions; i++) {
326
double score = similarity(suggestions[i]);
327
if (score < min) {
328
min = score;
329
pos = i;
330
}
331
}
332
if (score > min) {
333
suggestions[pos] = sel;
334
}
335
}
336
337
if (nsuggestions == 0) {
338
// Found no similar enough selections to suggest.
339
return;
340
}
341
342
// Sort found suggestions to suggest the best one first
343
SimilarityComparator sc(*this);
344
QuickSort::sort(suggestions, nsuggestions, sc, false);
345
346
out->print("Did you mean any of the following?");
347
for (size_t i = 0; i < nsuggestions; i++) {
348
char buf[128];
349
suggestions[i].describe_tags(buf, sizeof(buf));
350
out->print(" %s", buf);
351
}
352
}
353
354