1
+ // ===--- Histogram.h - Simple histogram for statistics ----------*- C++ -*-===//
2
+ //
3
+ // This source file is part of the Swift.org open source project
4
+ //
5
+ // Copyright (c) 2021 Apple Inc. and the Swift project authors
6
+ // Licensed under Apache License v2.0 with Runtime Library Exception
7
+ //
8
+ // See https://swift.org/LICENSE.txt for license information
9
+ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
+ //
11
+ // ===----------------------------------------------------------------------===//
12
+
13
+ #include " llvm/ADT/ArrayRef.h"
14
+
15
+ #ifndef SWIFT_HISTOGRAM_H
16
+ #define SWIFT_HISTOGRAM_H
17
+
18
+ #include " llvm/ADT/ArrayRef.h"
19
+ #include " llvm/ADT/StringRef.h"
20
+ #include " llvm/Support/raw_ostream.h"
21
+ #include < algorithm>
22
+ #include < vector>
23
+
24
+ namespace swift {
25
+
26
+ namespace rewriting {
27
+
28
+ // / A simple histogram that supports two operations: recording an element, and
29
+ // / printing a graphical representation.
30
+ // /
31
+ // / Used by the rewrite system to record various statistics, which are dumped
32
+ // / when the -analyze-requirement-machine frontend flag is used.
33
+ class Histogram {
34
+ unsigned Size;
35
+ unsigned Start;
36
+ std::vector<unsigned > Buckets;
37
+ unsigned OverflowBucket;
38
+
39
+ const unsigned MaxWidth = 40 ;
40
+
41
+ // / This is not really the base-10 logarithm, but rather the number of digits
42
+ // / in \p x when printed in base 10.
43
+ // /
44
+ // / So log10(0) == 1, log10(1) == 1, log10(10) == 2, etc.
45
+ static unsigned log10 (unsigned x) {
46
+ if (x == 0 )
47
+ return 1 ;
48
+ unsigned result = 0 ;
49
+ while (x != 0 ) {
50
+ result += 1 ;
51
+ x /= 10 ;
52
+ }
53
+ return result;
54
+ }
55
+
56
+ public:
57
+ // / Creates a histogram with \p size buckets, where the numbering begins at
58
+ // / \p start.
59
+ Histogram (unsigned size, unsigned start = 0 )
60
+ : Size(size),
61
+ Start (start),
62
+ Buckets(size, 0 ),
63
+ OverflowBucket(0 ) {
64
+ }
65
+
66
+ // / Adds an entry to the histogram. Asserts if the \p value is smaller than
67
+ // / Start. The value is allowed to be greater than or equal to Start + Size,
68
+ // / in which case it's counted in the OverflowBucket.
69
+ void add (unsigned value) {
70
+ assert (value >= Start);
71
+ value -= Start;
72
+ if (value >= Size)
73
+ ++OverflowBucket;
74
+ else
75
+ ++Buckets[value];
76
+ }
77
+
78
+ // / Print a nice-looking graphical representation of the histogram.
79
+ void dump (llvm::raw_ostream &out, const StringRef labels[] = {}) {
80
+ unsigned sumValues = 0 ;
81
+ unsigned maxValue = 0 ;
82
+ for (unsigned i = 0 ; i < Size; ++i) {
83
+ sumValues += Buckets[i];
84
+ maxValue = std::max (maxValue, Buckets[i]);
85
+ }
86
+ sumValues += OverflowBucket;
87
+ maxValue = std::max (maxValue, OverflowBucket);
88
+
89
+ size_t maxLabelWidth = 3 + log10 (Size + Start);
90
+ if (labels != nullptr ) {
91
+ for (unsigned i = 0 ; i < Size; ++i)
92
+ maxLabelWidth = std::max (labels[i].size (), maxLabelWidth);
93
+ }
94
+
95
+ out << std::string (maxLabelWidth, ' ' ) << " |" ;
96
+ out << std::string (std::min (MaxWidth, maxValue), ' ' );
97
+ out << maxValue << " \n " ;
98
+
99
+ out << std::string (maxLabelWidth, ' ' ) << " |" ;
100
+ out << std::string (std::min (MaxWidth, maxValue), ' ' );
101
+ out << " *\n " ;
102
+
103
+ out << std::string (maxLabelWidth, ' -' ) << " -+-" ;
104
+ out << std::string (std::min (MaxWidth, maxValue), ' -' ) << " \n " ;
105
+
106
+ auto scaledValue = [&](unsigned value) {
107
+ if (maxValue > MaxWidth) {
108
+ if (value != 0 ) {
109
+ // If the value is non-zero, print at least one '#'.
110
+ return std::max (1U , (value * MaxWidth) / maxValue);
111
+ }
112
+ }
113
+ return value;
114
+ };
115
+
116
+ for (unsigned i = 0 ; i < Size; ++i) {
117
+ if (labels) {
118
+ out << std::string (maxLabelWidth - labels[i].size (), ' ' );
119
+ out << labels[i];
120
+ } else {
121
+ unsigned key = i + Start;
122
+ out << std::string (maxLabelWidth - log10 (key), ' ' );
123
+ out << key;
124
+ }
125
+ out << " | " ;
126
+
127
+ unsigned value = scaledValue (Buckets[i]);
128
+ out << std::string (value, ' #' ) << " \n " ;
129
+ }
130
+
131
+ if (OverflowBucket > 0 ) {
132
+ out << " >= " << (Size + Start) << " | " ;
133
+
134
+ unsigned value = scaledValue (OverflowBucket);
135
+ out << std::string (value, ' #' ) << " \n " ;
136
+ }
137
+
138
+ out << std::string (maxLabelWidth, ' -' ) << " -+-" ;
139
+ out << std::string (std::min (MaxWidth, maxValue), ' -' ) << " \n " ;
140
+
141
+ out << std::string (maxLabelWidth, ' ' ) << " | " ;
142
+ out << " Total: " << sumValues << " \n " ;
143
+ }
144
+ };
145
+
146
+ } // end namespace rewriting
147
+
148
+ } // end namespace swift
149
+
150
+ #endif
0 commit comments