Skip to content

Commit b7c4d82

Browse files
committed
RequirementMachine: Add a simple Histogram data structure
1 parent fb5d180 commit b7c4d82

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
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

Comments
 (0)