yum-archive/TaSTT-Whisper

High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model

git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper

KonstantinA tool to summarize performance data into one table5483755

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