1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
using System.Globalization;
using System.Text.RegularExpressions;
namespace PerfSummary
{
enum eInputClip: byte
{
jfk,
columbia,
}
enum eWhisperModel: byte
{
medium,
large
}
struct LogName
{
public readonly eInputClip clip;
public readonly eWhisperModel model;
public readonly string gpu;
public override string ToString() => $"{clip}-{model}-{gpu}";
public static LogName? tryParse( string path )
{
string? ext = Path.GetExtension( path );
if( ext == null || !ext.Equals( ".txt", StringComparison.InvariantCultureIgnoreCase ) )
return null;
string name = Path.GetFileNameWithoutExtension( path );
string[] fields = name.Split( '-' );
if( fields.Length != 3 )
return null;
return new LogName( fields );
}
LogName( string[] fields )
{
clip = Enum.Parse<eInputClip>( fields[ 0 ] );
model = Enum.Parse<eWhisperModel>( fields[ 1 ] );
gpu = fields[ 2 ];
}
}
record class LogData
{
public LogName name { get; init; }
// The numbers are seconds
public double runComplete { get; init; }
public double encode { get; init; }
public double decode { get; init; }
// The numbers are megabytes
public double ram { get; init; }
public double vram { get; init; }
}
static class LogParser
{
public static IEnumerable<LogData> parse( string folder )
{
foreach( string path in Directory.EnumerateFiles( folder, "*.txt" ) )
{
LogName? name = LogName.tryParse( path );
if( name == null )
continue;
yield return parseFile( name.Value, path );
}
}
enum eSection: byte
{
CPU, GPU, Shaders, Memory
}
static readonly (string, eSection)[] sectionMarkers = new (string, eSection)[]
{
("CPU Tasks", eSection.CPU),
("GPU Tasks", eSection.GPU),
("Compute Shaders", eSection.Shaders),
("Memory Usage", eSection.Memory),
};
static bool tryParseSection( ref eSection? section, string line )
{
foreach( (string marker, eSection s) in sectionMarkers )
{
if( line.Contains( marker ) )
{
section = s;
return true;
}
}
return false;
}
static bool tryParseTime( ref double? val, string key, string line )
{
if( !line.StartsWith( key ) )
return false;
if( !char.IsWhiteSpace( line[ key.Length ] ) )
return false;
line = line.Substring( key.Length ).TrimStart();
int comma = line.IndexOf( ',' );
if( comma > 0 )
line = line.Substring( 0, comma );
string[] fields = line.Split( ' ', StringSplitOptions.RemoveEmptyEntries );
if( fields.Length != 2 )
throw new ArgumentException();
double v = double.Parse( fields[ 0 ], CultureInfo.InvariantCulture );
switch( fields[ 1 ] )
{
case "seconds":
val = v;
return true;
case "milliseconds":
val = v / 1E3;
return true;
case "microseconds":
val = v / 1E6;
return true;
}
throw new ArgumentException();
}
static readonly Regex reMemory = new Regex( @"^Total\s+([0-9\.]+)\s+(\S+)\s+RAM, ([0-9\.]+)\s+(\S+)\s+VRAM$" );
static double parseMemory( Match m, int iv )
{
double v = double.Parse( m.Groups[ iv ].Value, CultureInfo.InvariantCulture );
string u = m.Groups[ iv + 1 ].Value;
switch( u )
{
case "bytes":
return v / ( 1 << 20 );
case "KB":
return v / ( 1 << 10 );
case "MB":
return v;
case "GB":
return v * ( 1 << 10 );
}
throw new ArgumentException();
}
static bool tryParseMemory( ref double? ram, ref double? vram, string line )
{
Match m = reMemory.Match( line );
if( !m.Success )
return false;
ram = parseMemory( m, 1 );
vram = parseMemory( m, 3 );
return true;
}
static LogData parseFile( in LogName name, string path )
{
using var reader = File.OpenText( path );
double? runComplete = null;
double? encode = null;
double? decode = null;
double? ram = null;
double? vram = null;
eSection? section = null;
while( true )
{
string? line = reader.ReadLine();
if( line == null )
break;
if( string.IsNullOrEmpty( line ) )
continue;
if( tryParseSection( ref section, line ) )
continue;
switch( section )
{
case eSection.CPU:
tryParseTime( ref runComplete, "RunComplete", line );
break;
case eSection.GPU:
tryParseTime( ref encode, "Encode", line );
tryParseTime( ref decode, "Decode", line );
break;
case eSection.Memory:
tryParseMemory( ref ram, ref vram, line );
break;
}
}
if( null == runComplete || null == encode || null == decode || null == ram || null == vram )
throw new ArgumentException();
return new LogData()
{
name = name,
runComplete = runComplete.Value,
encode = encode.Value,
decode = decode.Value,
ram = ram.Value,
vram = vram.Value,
};
}
}
}
|