15
15
*/
16
16
17
17
import React from "react"
18
- import { Chart , ChartAxis , ChartArea } from "@patternfly/react-charts"
18
+ import { Chart , ChartAxis , ChartArea , ChartAreaProps , ChartAxisProps } from "@patternfly/react-charts"
19
19
import { Log } from "../types"
20
20
21
21
import "../../web/scss/components/Dashboard/Charts.scss"
@@ -24,111 +24,144 @@ type Props = {
24
24
logs : Log [ ]
25
25
}
26
26
27
- const generateXFormat = ( logs : Log [ ] ) => {
28
- return [
29
- ...new Set (
30
- logs
31
- . filter ( ( item ) => item . utilizationGPU > 0 )
32
- . map ( ( item ) => `${ new Date ( item . timestamp ) . getHours ( ) } :${ new Date ( item . timestamp ) . getMinutes ( ) } ` )
33
- ) ,
27
+ export default class GPUChart extends React . PureComponent < Props > {
28
+ private readonly colors = [
29
+ "var(--color-base04)" ,
30
+ "var(--color-latency-3)" ,
31
+ "var(--color-latency-1)" ,
32
+ "var(--color-latency-4)" ,
34
33
]
35
- }
34
+ private readonly labelColor = "var(--color-text-01)"
35
+ private readonly fontFamily = "var(--font-sans-serif)"
36
36
37
- const generateXValues = ( logs : Log [ ] ) => {
38
- return [ ...new Set ( logs . filter ( ( item ) => item . utilizationGPU > 0 ) . map ( ( item ) => item . timestamp ) ) ]
39
- }
37
+ private readonly axisStyle : ChartAxisProps [ "style" ] = {
38
+ tickLabels : { fontSize : 9 , fontFamily : this . fontFamily , fill : this . labelColor } ,
39
+ axisLabel : { fontSize : 11 , fontFamily : this . fontFamily , fill : this . labelColor } ,
40
+ }
40
41
41
- const axisStyle = { tickLabels : { fontSize : 9 } }
42
- const yTickValues = [ 0 , 25 , 50 , 75 , 100 ]
43
- const yTickLabels = yTickValues . map ( ( _ ) => ` ${ _ } %` )
42
+ private axisStyleWithGrid : ChartAxisProps [ "style" ] = Object . assign ( { } , this . axisStyle , {
43
+ grid : { strokeWidth : 1 , stroke : this . colors [ 0 ] } ,
44
+ } )
44
45
45
- const styles = {
46
- memory : { data : { fill : "var(--color-chart-0)" } } ,
47
- gpu : { data : { fill : "var(--color-chart-1)" } } ,
48
- }
46
+ private readonly padding = {
47
+ bottom : 25 ,
48
+ left : 60 ,
49
+ right : 25 ,
50
+ top : 10 ,
51
+ }
49
52
50
- const GPUChart = ( props : Props ) => {
51
- const { logs } = props
52
- return (
53
- < div style = { { height : "auto" , width : "100%" , display : "flex" , flexDirection : "column" } } >
54
- < Chart
55
- ariaTitle = "GPU Utilization"
56
- ariaDesc = "Chart showing GPU utilization over time"
57
- height = { 135 }
58
- width = { 1000 }
59
- maxDomain = { { y : 100 } }
60
- minDomain = { { y : 0 } }
61
- padding = { {
62
- bottom : 25 ,
63
- left : 60 ,
64
- right : 5 ,
65
- top : 10 ,
66
- } }
67
- >
68
- < ChartAxis
69
- label = "GPU"
70
- dependentAxis
71
- showGrid
72
- style = { axisStyle }
73
- tickValues = { yTickValues }
74
- tickFormat = { yTickLabels }
75
- />
76
- < ChartAxis
77
- scale = "time"
78
- style = { axisStyle }
79
- tickValues = { generateXValues ( logs ) }
80
- tickFormat = { generateXFormat ( logs ) }
81
- tickCount = { generateXFormat ( logs ) . length }
82
- />
83
- < ChartArea
84
- style = { styles . gpu }
85
- data = { logs . map ( ( log ) => ( {
86
- name : log . gpuType ,
87
- x : log . timestamp ,
88
- y : log . utilizationGPU ,
89
- } ) ) }
90
- />
91
- </ Chart >
53
+ private readonly styles = {
54
+ utilizationMemory : this . style ( this . colors [ 1 ] ) ,
55
+ utilizationGPU : this . style ( this . colors [ 2 ] ) ,
56
+ temperatureGPU : this . style ( this . colors [ 3 ] ) ,
57
+ cluster : undefined ,
58
+ timestamp : undefined ,
59
+ gpuType : undefined ,
60
+ totalMemory : undefined ,
61
+ }
62
+
63
+ private readonly dimensions = {
64
+ width : 400 ,
65
+ height : 90 ,
66
+ }
67
+
68
+ private readonly formatters = {
69
+ celsius : ( value : number ) => value + "C" ,
70
+ percentage : ( value : number ) => value + "%" ,
71
+ timestamp : ( timestamp : number ) => `${ new Date ( timestamp ) . getHours ( ) } :${ new Date ( timestamp ) . getMinutes ( ) } ` ,
72
+ }
73
+
74
+ private readonly minDomain = {
75
+ percentage : { y : 0 } ,
76
+ celsius : undefined ,
77
+ timestamp : undefined ,
78
+ }
79
+ private readonly maxDomain = {
80
+ percentage : { y : 100 } ,
81
+ celsius : undefined ,
82
+ timestamp : undefined ,
83
+ }
84
+
85
+ private xAxis ( ) {
86
+ return (
87
+ < ChartAxis
88
+ scale = "time"
89
+ style = { this . axisStyle }
90
+ tickValues = { this . props . logs . map ( ( item ) => item . timestamp ) }
91
+ tickFormat = { this . formatters . timestamp }
92
+ tickCount = { 5 }
93
+ />
94
+ )
95
+ }
96
+
97
+ private style ( color : string ) : ChartAreaProps [ "style" ] {
98
+ return { data : { stroke : color , fill : color } }
99
+ }
100
+
101
+ private chart (
102
+ title : string ,
103
+ desc : string ,
104
+ label : string ,
105
+ formatter : keyof typeof this . formatters ,
106
+ series : keyof Log ,
107
+ tickCount ?: number
108
+ ) {
109
+ return (
92
110
< Chart
93
- ariaTitle = "GPU Memory Utilization"
94
- ariaDesc = "Chart showing GPU memory utilization over time"
95
- height = { 135 }
96
- width = { 1000 }
97
- maxDomain = { { y : 100 } }
98
- minDomain = { { y : 0 } }
99
- padding = { {
100
- bottom : 25 ,
101
- left : 60 ,
102
- right : 5 ,
103
- top : 10 ,
104
- } }
111
+ ariaTitle = { title }
112
+ ariaDesc = { desc }
113
+ height = { this . dimensions . height }
114
+ width = { this . dimensions . width }
115
+ maxDomain = { this . maxDomain [ formatter ] }
116
+ minDomain = { this . minDomain [ formatter ] }
117
+ padding = { this . padding }
105
118
>
106
119
< ChartAxis
107
- label = "Memory"
120
+ label = { label }
108
121
dependentAxis
109
- showGrid
110
- style = { axisStyle }
111
- tickValues = { yTickValues }
112
- tickFormat = { yTickLabels }
113
- />
114
- < ChartAxis
115
- scale = "time"
116
- style = { axisStyle }
117
- tickValues = { generateXValues ( logs ) }
118
- tickFormat = { generateXFormat ( logs ) }
119
- tickCount = { generateXFormat ( logs ) . length }
122
+ style = { this . axisStyleWithGrid }
123
+ tickFormat = { this . formatters [ formatter ] }
124
+ tickCount = { tickCount }
120
125
/>
126
+ { this . xAxis ( ) }
121
127
< ChartArea
122
- style = { styles . memory }
123
- data = { logs . map ( ( log ) => ( {
128
+ style = { this . styles [ series ] }
129
+ data = { this . props . logs . map ( ( log ) => ( {
124
130
name : log . gpuType ,
125
131
x : log . timestamp ,
126
- y : log . utilizationMemory ,
132
+ y : log [ series ] ,
127
133
} ) ) }
128
134
/>
129
135
</ Chart >
130
- </ div >
131
- )
132
- }
136
+ )
137
+ }
133
138
134
- export default GPUChart
139
+ public render ( ) {
140
+ return (
141
+ < div className = "codeflare-chart-container" >
142
+ { this . chart (
143
+ "GPU Utilization" ,
144
+ "Chart showing GPU utilization over time" ,
145
+ "Utilization" ,
146
+ "percentage" ,
147
+ "utilizationGPU"
148
+ ) }
149
+ { this . chart (
150
+ "GPU Memory Utilization" ,
151
+ "Chart showing GPU memory utilization over time" ,
152
+ "Memory" ,
153
+ "percentage" ,
154
+ "utilizationMemory"
155
+ ) }
156
+ { this . chart (
157
+ "GPU Temperature" ,
158
+ "Chart showing GPU temperature over time" ,
159
+ "Temperature" ,
160
+ "celsius" ,
161
+ "temperatureGPU" ,
162
+ 3
163
+ ) }
164
+ </ div >
165
+ )
166
+ }
167
+ }
0 commit comments