1 //===-- xray-graph.cpp: XRay Function Call Graph Renderer -----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // A class to get a color from a specified gradient.
11 //===----------------------------------------------------------------------===//
13 #include "xray-color-helper.h"
14 #include "llvm/Support/FormatVariadic.h"
15 #include "llvm/Support/raw_ostream.h"
21 // Sequential ColorMaps, which are used to represent information
22 // from some minimum to some maximum.
24 const std::tuple
<uint8_t, uint8_t, uint8_t> SequentialMaps
[][9] = {
25 {// The greys color scheme from http://colorbrewer2.org/
26 std::make_tuple(255, 255, 255), std::make_tuple(240, 240, 240),
27 std::make_tuple(217, 217, 217), std::make_tuple(189, 189, 189),
28 std::make_tuple(150, 150, 150), std::make_tuple(115, 115, 115),
29 std::make_tuple(82, 82, 82), std::make_tuple(37, 37, 37),
30 std::make_tuple(0, 0, 0)},
31 {// The OrRd color scheme from http://colorbrewer2.org/
32 std::make_tuple(255, 247, 236), std::make_tuple(254, 232, 200),
33 std::make_tuple(253, 212, 158), std::make_tuple(253, 187, 132),
34 std::make_tuple(252, 141, 89), std::make_tuple(239, 101, 72),
35 std::make_tuple(215, 48, 31), std::make_tuple(179, 0, 0),
36 std::make_tuple(127, 0, 0)},
37 {// The PuBu color scheme from http://colorbrewer2.org/
38 std::make_tuple(255, 247, 251), std::make_tuple(236, 231, 242),
39 std::make_tuple(208, 209, 230), std::make_tuple(166, 189, 219),
40 std::make_tuple(116, 169, 207), std::make_tuple(54, 144, 192),
41 std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
42 std::make_tuple(2, 56, 88)}};
44 // Sequential Maps extend the last colors given out of range inputs.
45 const std::tuple
<uint8_t, uint8_t, uint8_t> SequentialBounds
[][2] = {
46 {// The Bounds for the greys color scheme
47 std::make_tuple(255, 255, 255), std::make_tuple(0, 0, 0)},
48 {// The Bounds for the OrRd color Scheme
49 std::make_tuple(255, 247, 236), std::make_tuple(127, 0, 0)},
50 {// The Bounds for the PuBu color Scheme
51 std::make_tuple(255, 247, 251), std::make_tuple(2, 56, 88)}};
53 ColorHelper::ColorHelper(ColorHelper::SequentialScheme S
)
54 : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps
[static_cast<int>(S
)]),
55 BoundMap(SequentialBounds
[static_cast<int>(S
)]) {}
57 // Diverging ColorMaps, which are used to represent information
58 // representing differenes, or a range that goes from negative to positive.
59 // These take an input in the range [-1,1].
61 const std::tuple
<uint8_t, uint8_t, uint8_t> DivergingCoeffs
[][11] = {
62 {// The PiYG color scheme from http://colorbrewer2.org/
63 std::make_tuple(142, 1, 82), std::make_tuple(197, 27, 125),
64 std::make_tuple(222, 119, 174), std::make_tuple(241, 182, 218),
65 std::make_tuple(253, 224, 239), std::make_tuple(247, 247, 247),
66 std::make_tuple(230, 245, 208), std::make_tuple(184, 225, 134),
67 std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
68 std::make_tuple(39, 100, 25)}};
70 // Diverging maps use out of bounds ranges to show missing data. Missing Right
71 // Being below min, and missing left being above max.
72 const std::tuple
<uint8_t, uint8_t, uint8_t> DivergingBounds
[][2] = {
73 {// The PiYG color scheme has green and red for missing right and left
75 std::make_tuple(255, 0, 0), std::make_tuple(0, 255, 0)}};
77 ColorHelper::ColorHelper(ColorHelper::DivergingScheme S
)
78 : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs
[static_cast<int>(S
)]),
79 BoundMap(DivergingBounds
[static_cast<int>(S
)]) {}
81 // Takes a tuple of uint8_ts representing a color in RGB and converts them to
82 // HSV represented by a tuple of doubles
83 static std::tuple
<double, double, double>
84 convertToHSV(const std::tuple
<uint8_t, uint8_t, uint8_t> &Color
) {
85 double Scaled
[3] = {std::get
<0>(Color
) / 255.0, std::get
<1>(Color
) / 255.0,
86 std::get
<2>(Color
) / 255.0};
89 for (int i
= 1; i
< 3; ++i
) {
90 if (Scaled
[i
] < Scaled
[Min
])
92 if (Scaled
[i
] > Scaled
[Max
])
96 double C
= Scaled
[Max
] - Scaled
[Min
];
99 (C
== 0) ? 0 : (Scaled
[(Max
+ 1) % 3] - Scaled
[(Max
+ 2) % 3]) / C
;
100 HPrime
= HPrime
+ 2.0 * Max
;
102 double H
= (HPrime
< 0) ? (HPrime
+ 6.0) * 60
103 : HPrime
* 60; // Scale to between 0 and 360
104 double V
= Scaled
[Max
];
106 double S
= (V
== 0.0) ? 0.0 : C
/ V
;
108 return std::make_tuple(H
, S
, V
);
111 // Takes a double precision number, clips it between 0 and 1 and then converts
112 // that to an integer between 0x00 and 0xFF with proxpper rounding.
113 static uint8_t unitIntervalTo8BitChar(double B
) {
114 double n
= std::max(std::min(B
, 1.0), 0.0);
115 return static_cast<uint8_t>(255 * n
+ 0.5);
118 // Takes a typle of doubles representing a color in HSV and converts them to
119 // RGB represented as a tuple of uint8_ts
120 static std::tuple
<uint8_t, uint8_t, uint8_t>
121 convertToRGB(const std::tuple
<double, double, double> &Color
) {
122 const double &H
= std::get
<0>(Color
);
123 const double &S
= std::get
<1>(Color
);
124 const double &V
= std::get
<2>(Color
);
128 double HPrime
= H
/ 60;
129 double X
= C
* (1 - std::abs(std::fmod(HPrime
, 2.0) - 1));
132 int HPrimeInt
= static_cast<int>(HPrime
);
133 if (HPrimeInt
% 2 == 0) {
134 RGB1
[(HPrimeInt
/ 2) % 3] = C
;
135 RGB1
[(HPrimeInt
/ 2 + 1) % 3] = X
;
136 RGB1
[(HPrimeInt
/ 2 + 2) % 3] = 0.0;
138 RGB1
[(HPrimeInt
/ 2) % 3] = X
;
139 RGB1
[(HPrimeInt
/ 2 + 1) % 3] = C
;
140 RGB1
[(HPrimeInt
/ 2 + 2) % 3] = 0.0;
144 double RGB2
[3] = {RGB1
[0] + Min
, RGB1
[1] + Min
, RGB1
[2] + Min
};
146 return std::make_tuple(unitIntervalTo8BitChar(RGB2
[0]),
147 unitIntervalTo8BitChar(RGB2
[1]),
148 unitIntervalTo8BitChar(RGB2
[2]));
151 // The Hue component of the HSV interpolation Routine
152 static double interpolateHue(double H0
, double H1
, double T
) {
162 return H0
+ T
* (H1
- H0
);
165 return std::fmod(H0
+ T
* (H1
- H0
) + 720, 360);
169 // Interpolates between two HSV Colors both represented as a tuple of doubles
170 // Returns an HSV Color represented as a tuple of doubles
171 static std::tuple
<double, double, double>
172 interpolateHSV(const std::tuple
<double, double, double> &C0
,
173 const std::tuple
<double, double, double> &C1
, double T
) {
174 double H
= interpolateHue(std::get
<0>(C0
), std::get
<0>(C1
), T
);
175 double S
= std::get
<1>(C0
) + T
* (std::get
<1>(C1
) - std::get
<1>(C0
));
176 double V
= std::get
<2>(C0
) + T
* (std::get
<2>(C1
) - std::get
<2>(C0
));
177 return std::make_tuple(H
, S
, V
);
180 // Get the Color as a tuple of uint8_ts
181 std::tuple
<uint8_t, uint8_t, uint8_t>
182 ColorHelper::getColorTuple(double Point
) const {
183 assert(!ColorMap
.empty() && "ColorMap must not be empty!");
184 assert(!BoundMap
.empty() && "BoundMap must not be empty!");
191 size_t MaxIndex
= ColorMap
.size() - 1;
192 double IntervalWidth
= MaxIn
- MinIn
;
193 double OffsetP
= Point
- MinIn
;
194 double SectionWidth
= IntervalWidth
/ static_cast<double>(MaxIndex
);
195 size_t SectionNo
= std::floor(OffsetP
/ SectionWidth
);
196 double T
= (OffsetP
- SectionNo
* SectionWidth
) / SectionWidth
;
198 auto &RGBColor0
= ColorMap
[SectionNo
];
199 auto &RGBColor1
= ColorMap
[std::min(SectionNo
+ 1, MaxIndex
)];
201 auto HSVColor0
= convertToHSV(RGBColor0
);
202 auto HSVColor1
= convertToHSV(RGBColor1
);
204 auto InterpolatedHSVColor
= interpolateHSV(HSVColor0
, HSVColor1
, T
);
205 return convertToRGB(InterpolatedHSVColor
);
208 // A helper method to convert a color represented as tuple of uint8s to a hex
211 ColorHelper::getColorString(std::tuple
<uint8_t, uint8_t, uint8_t> t
) {
212 return std::string(llvm::formatv("#{0:X-2}{1:X-2}{2:X-2}", std::get
<0>(t
),
213 std::get
<1>(t
), std::get
<2>(t
)));
216 // Gets a color in a gradient given a number in the interval [0,1], it does this
217 // by evaluating a polynomial which maps [0, 1] -> [0, 1] for each of the R G
218 // and B values in the color. It then converts this [0,1] colors to a 24 bit
219 // color as a hex string.
220 std::string
ColorHelper::getColorString(double Point
) const {
221 return getColorString(getColorTuple(Point
));