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