1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.IO; 10 using System.Linq; 11 using System.Runtime.InteropServices; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Exceptions; 14 using Antmicro.Renode.Peripherals.CPU; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.Logging.Profiling 18 { 19 public class Profiler : IDisposable 20 { Profiler(IMachine machine, string outputPath)21 public Profiler(IMachine machine, string outputPath) 22 { 23 this.machine = machine; 24 25 try 26 { 27 output = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete); 28 } 29 catch(IOException ex) 30 { 31 throw new RecoverableException(ex); 32 } 33 34 EnableProfiling(); 35 machine.PeripheralsChanged += OnPeripheralsChanged; 36 } 37 Log(BaseEntry entry)38 public void Log(BaseEntry entry) 39 { 40 lock(locker) 41 { 42 if(!headerWritten) 43 { 44 WriteHeader(); 45 } 46 var bytes = Serialize(entry); 47 output.Write(bytes, 0, bytes.Length); 48 } 49 } 50 Dispose()51 public void Dispose() 52 { 53 output.Flush(); 54 output.Dispose(); 55 } 56 EnableProfiling()57 private void EnableProfiling() 58 { 59 var cpus = machine.GetPeripheralsOfType<ICPUWithMetrics>(); 60 foreach(var cpu in cpus) 61 { 62 cpu.EnableProfiling(); 63 } 64 } 65 OnPeripheralsChanged(IMachine machine, PeripheralsChangedEventArgs args)66 private void OnPeripheralsChanged(IMachine machine, PeripheralsChangedEventArgs args) 67 { 68 if(args.Operation != PeripheralsChangedEventArgs.PeripheralChangeType.Addition) 69 { 70 return; 71 } 72 73 var cpu = args.Peripheral as ICPUWithMetrics; 74 if(cpu != null) 75 { 76 cpu.EnableProfiling(); 77 } 78 } 79 WriteHeader()80 private void WriteHeader() 81 { 82 headerWritten = true; 83 var header = new ProfilerHeader(); 84 header.RegisterPeripherals(machine); 85 output.Write(header.Bytes, 0, header.Bytes.Length); 86 } 87 Serialize(object target)88 private byte[] Serialize(object target) 89 { 90 var size = Marshal.SizeOf(target); 91 var result = new byte[size]; 92 var handler = default(GCHandle); 93 94 try 95 { 96 handler = GCHandle.Alloc(result, GCHandleType.Pinned); 97 Marshal.StructureToPtr(target, handler.AddrOfPinnedObject(), false); 98 } 99 finally 100 { 101 if(handler.IsAllocated) 102 { 103 handler.Free(); 104 } 105 } 106 107 return result; 108 } 109 110 private bool headerWritten; 111 112 private readonly static object locker = new object(); 113 private readonly FileStream output; 114 private readonly IMachine machine; 115 } 116 } 117