PageRenderTime 53ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/src/QueryFx/QueryCompiler.cs

http://svcperf.codeplex.com
C# | 371 lines | 321 code | 42 blank | 8 comment | 20 complexity | cb652a7ee7b7a7f10637d562f401552a MD5 | raw file
  1. namespace EtlViewer.QueryFx
  2. {
  3. using Microsoft.CSharp;
  4. using System;
  5. using System.CodeDom.Compiler;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reactive;
  10. using System.Reflection;
  11. using System.Text;
  12. using Tx.Windows;
  13. public class QueryCompiler
  14. {
  15. public static string TempAssemblyCache
  16. {
  17. get
  18. {
  19. return App.TempFiles + Path.DirectorySeparatorChar + "TemporaryCompiledAssemblies";
  20. }
  21. }
  22. static Dictionary<string, Assembly> AssemblyCache = new Dictionary<string, Assembly>();
  23. static QueryCompiler()
  24. {
  25. AppDomain currentDomain = AppDomain.CurrentDomain;
  26. currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
  27. }
  28. static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
  29. {
  30. string folderPath = Directory.GetCurrentDirectory();
  31. string assemblyPath = Path.Combine(folderPath, TempAssemblyCache, new AssemblyName(args.Name).Name + ".dll");
  32. if (File.Exists(assemblyPath) == false) return null;
  33. Assembly assembly = Assembly.LoadFrom(assemblyPath);
  34. return assembly;
  35. }
  36. internal static void Compile(string[] fileNames,
  37. string linqFile,
  38. TextWriter outputStream,
  39. TextWriter errorStream,
  40. Type[] knownTypes = null,
  41. DateTime? startTime = null,
  42. DateTime? endTime = null)
  43. {
  44. StringWriter errorLogger = new StringWriter();
  45. string query = LinqpadHelpers.ExtractQuery(linqFile, errorLogger);
  46. Playback playback = new Playback();
  47. foreach (string file in fileNames)
  48. {
  49. string extension = Path.GetExtension(file);
  50. if (string.Equals(".etl", extension, StringComparison.InvariantCultureIgnoreCase))
  51. {
  52. playback.AddEtlFiles(file);
  53. }
  54. //else if (string.Equals(".csv", extension, StringComparison.InvariantCultureIgnoreCase))
  55. //{
  56. // playback.AddCsvFile(file);
  57. //}
  58. }
  59. Dictionary<string, object> playbackProperties = new Dictionary<string, object>();
  60. if (startTime.HasValue)
  61. {
  62. playbackProperties.Add("StartTime", startTime.Value);
  63. }
  64. if (endTime.HasValue)
  65. {
  66. playbackProperties.Add("EndTime", endTime.Value);
  67. }
  68. playback.KnownTypes = knownTypes;
  69. CsvWriterSettings csvsettings = new CsvWriterSettings
  70. {
  71. Writer = outputStream
  72. };
  73. Func<Type, object, Action<object>> onDumpStartCsv = (t, result) =>
  74. {
  75. CsvHelper.PrintHeader(t, csvsettings);
  76. Action<object> onNext = (o) =>
  77. {
  78. CsvHelper.Dump(o, csvsettings);
  79. };
  80. return onNext;
  81. };
  82. CompileAndRun(new QueryExecutionContext(playback, onDumpStartCsv),
  83. query,
  84. errorStream,
  85. errorStream,
  86. playbackProperties);
  87. }
  88. public static bool CompileAndRun(QueryExecutionContext context,
  89. string query,
  90. TextWriter errorLogger,
  91. TextWriter logger,
  92. Dictionary<string, object> playbackProperties = null)
  93. {
  94. try
  95. {
  96. EnsureTemporaryCache();
  97. Assembly assembly = null;
  98. Logger.Log("Compiling Query \n" + query);
  99. if (string.IsNullOrEmpty(query))
  100. {
  101. errorLogger.Write("No query present to execute.");
  102. return false;
  103. }
  104. if (!AssemblyCache.TryGetValue(query, out assembly))
  105. {
  106. string usings = GetUsings();
  107. assembly = GenerateAssembly(usings, query, errorLogger, logger);
  108. if (assembly != null)
  109. {
  110. AssemblyCache[query] = assembly;
  111. }
  112. }
  113. if (assembly != null)
  114. {
  115. object t = Activator.CreateInstance(assembly.GetType("QueryExecutionTemplate.PlaybackWrapper"), context.Playback, logger);
  116. if (playbackProperties != null)
  117. {
  118. foreach (var extraParam in playbackProperties)
  119. {
  120. t.GetType().GetProperty(extraParam.Key).SetValue(t, extraParam.Value, null);
  121. }
  122. }
  123. QueryExecutionContext.Current = context;
  124. bool result = (bool)t.GetType().GetMethod("CompileQuery").Invoke(t, null);
  125. if (result == false)
  126. {
  127. Exception ex = (Exception)t.GetType().GetProperty("Exception").GetValue(t, null);
  128. context.SetException(ex);
  129. }
  130. else
  131. {
  132. context.Run();
  133. }
  134. return result;
  135. }
  136. }
  137. catch (Exception ex)
  138. {
  139. context.SetException(ex);
  140. errorLogger.WriteLine(ex.Message);
  141. }
  142. return false;
  143. }
  144. private static string GetUsings()
  145. {
  146. StringBuilder builder = new StringBuilder();
  147. foreach (var providerName in ManifestCompiler.GetProviders())
  148. {
  149. builder.Append("using Tx.Windows.").Append(providerName).AppendLine(";");
  150. }
  151. return builder.ToString();
  152. }
  153. private static void EnsureTemporaryCache()
  154. {
  155. if (!Directory.Exists(TempAssemblyCache))
  156. {
  157. Directory.CreateDirectory(TempAssemblyCache);
  158. }
  159. }
  160. private static Assembly GenerateAssembly(string usings,
  161. string query,
  162. TextWriter errorLogger,
  163. TextWriter compilerOutput)
  164. {
  165. Assembly assembly = null;
  166. string location = TempAssemblyCache + "\\" + query.GetHashCode() + ".dll";
  167. var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
  168. var parameters = new CompilerParameters(QueryCompiler.GetAssemblies(), location, true);
  169. parameters.GenerateInMemory = true;
  170. string source = usings + templateProlog + query + templateEpilog;
  171. CompilerResults results = csc.CompileAssemblyFromSource(parameters, source);
  172. results.Errors.Cast<CompilerError>().ToList().ForEach(error => errorLogger.WriteLine(error.ErrorText));
  173. if (results.Errors.Count == 0)
  174. {
  175. assembly = results.CompiledAssembly;
  176. }
  177. return assembly;
  178. }
  179. internal static string[] GetAssemblyLocations()
  180. {
  181. return new string[] {
  182. typeof(System.Reactive.Observer).Assembly.Location, // "Reactive"
  183. typeof(System.Reactive.Linq.Observable).Assembly.Location, // "Reactive"
  184. typeof(System.Reactive.Concurrency.IScheduler).Assembly.Location, // Reactive.Interfaces
  185. typeof(Tx.Windows.SystemEvent).Assembly.Location, // Rx.Tx.Etw.dll
  186. typeof(System.Reactive.Playback).Assembly.Location, // Playback
  187. typeof(EtlViewerQuery.DurationItem).Assembly.Location, // QueryExtensions
  188. };
  189. }
  190. private static string[] GetAssemblies()
  191. {
  192. List<string> assemblies = new List<string>();
  193. assemblies.Add("mscorlib.dll");
  194. assemblies.Add("System.dll");
  195. assemblies.Add("System.Core.dll");
  196. foreach (string location in GetAssemblyLocations())
  197. {
  198. assemblies.Add(location);
  199. }
  200. foreach (string assembly in ManifestCompiler.GetGeneratedAssemblies())
  201. {
  202. assemblies.Add(assembly);
  203. }
  204. return assemblies.ToArray();
  205. }
  206. const string templateProlog = @"
  207. //We need to access the internal anonymous types in graph generation.
  208. [assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""SvcPerfUI"")]
  209. [assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""EventSeries"")]
  210. namespace QueryExecutionTemplate
  211. {
  212. using System;
  213. using System.Collections.Generic;
  214. using System.IO;
  215. using System.Linq;
  216. using System.Linq.Expressions;
  217. using System.Reflection;
  218. using System.Text;
  219. using System.Reactive;
  220. using System.Reactive.Linq;
  221. using EtlViewer.QueryFx;
  222. using EtlViewerQuery;
  223. using Tx.Windows;
  224. class PlaybackWrapper
  225. {
  226. #region WrapperFunctions
  227. Playback _playback;
  228. TextWriter logger;
  229. public Exception Exception{ get; set; }
  230. public PlaybackWrapper(Playback playback, TextWriter logger = null)
  231. {
  232. this.playback = playback;
  233. this.logger = logger;
  234. }
  235. // This is the actual underlying property
  236. // we provide both cases so that the user can easily
  237. // access the this.Playback or this.playback
  238. public Playback playback
  239. {
  240. get
  241. {
  242. if(this._playback == null)
  243. {
  244. throw new PlaybackUninitializedException();
  245. }
  246. return this._playback;
  247. }
  248. set
  249. {
  250. this._playback = value;
  251. }
  252. }
  253. public Playback Playback
  254. {
  255. get{ return this.playback; }
  256. set{ this.playback = value; }
  257. }
  258. public DateTime StartTime
  259. {
  260. get { return playback.StartTime.DateTime; }
  261. set { playback.StartTime = value; }
  262. }
  263. public void Run()
  264. {
  265. playback.Run();
  266. }
  267. public void Start()
  268. {
  269. playback.Start();
  270. }
  271. #endregion
  272. #region EtwSystem
  273. public IObservable<T> GetEtwStream<T>()
  274. {
  275. return playback.GetObservable<T>();
  276. }
  277. public IObservable<T> GetObservable<T>()
  278. {
  279. return playback.GetObservable<T>();
  280. }
  281. #endregion
  282. public bool CompileQuery()
  283. {
  284. try
  285. {
  286. this.CompileQueryAndRunInternal();
  287. return true;
  288. }
  289. catch(Exception ex)
  290. {
  291. this.Exception = ex;
  292. if(logger != null)
  293. {
  294. logger.WriteLine(""##################"");
  295. logger.WriteLine(""Exception"");
  296. logger.WriteLine(ex.ToString());
  297. logger.WriteLine(ex.StackTrace.ToString());
  298. logger.WriteLine(""##################"");
  299. }
  300. }
  301. return false;
  302. }
  303. void CompileQueryAndRunInternal()
  304. {
  305. logger.WriteLine(""#Starting Playback"");
  306. logger.WriteLine(""##################"");
  307. ";
  308. const string templateEpilog = @"
  309. logger.WriteLine(""##################"");
  310. }
  311. }
  312. }
  313. ";
  314. }
  315. public class PlaybackUninitializedException : Exception
  316. {
  317. public PlaybackUninitializedException()
  318. {
  319. }
  320. }
  321. }