Skip to content

Commit

Permalink
Merge pull request #56 from jonnew/memory-usage-monitor
Browse files Browse the repository at this point in the history
Add memory usage monitor support
  • Loading branch information
glopesdev authored Feb 27, 2024
2 parents 4282c0c + 767698e commit 0985fbb
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
4 changes: 4 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureBreakoutBoard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ public class ConfigureBreakoutBoard : HubDeviceFactory
[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureAnalogIO AnalogIO { get; set; } = new();

[TypeConverter(typeof(HubDeviceConverter))]
public ConfigureMemoryMonitor MemoryMonitor { get; set; } = new();

internal override IEnumerable<IDeviceConfiguration> GetDevices()
{
yield return Heartbeat;
yield return AnalogIO;
yield return MemoryMonitor;
}
}
}
57 changes: 57 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureMemoryMonitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.ComponentModel;
using Bonsai;

namespace OpenEphys.Onix
{
public class ConfigureMemoryMonitor : SingleDeviceFactory
{

public ConfigureMemoryMonitor()
: base(typeof(MemoryMonitor))
{
DeviceAddress = 10;
}

[Category(ConfigurationCategory)]
[Description("Specifies whether the monitor device is enabled.")]
public bool Enable { get; set; } = false;

[Range(1, 1000)]
[Category(ConfigurationCategory)]
[Description("Frequency at which memory usage is recorded (Hz).")]
public uint SampleFrequency { get; set; } = 10;

public override IObservable<ContextTask> Process(IObservable<ContextTask> source)
{
var deviceName = DeviceName;
var deviceAddress = DeviceAddress;
return source.ConfigureDevice(context =>
{
var device = context.GetDeviceContext(deviceAddress, MemoryMonitor.ID);
device.WriteRegister(MemoryMonitor.ENABLE, 1);
device.WriteRegister(MemoryMonitor.CLK_DIV, device.ReadRegister(MemoryMonitor.CLK_HZ) / SampleFrequency);

return DeviceManager.RegisterDevice(deviceName, device, DeviceType);
});
}
}

static class MemoryMonitor
{
public const int ID = 28;

public const uint ENABLE = 0; // Enable the monitor
public const uint CLK_DIV = 1; // Sample clock divider ratio. Values less than CLK_HZ / 10e6 Hz will result in 1kHz.
public const uint CLK_HZ = 2; // The frequency parameter, CLK_HZ, used in the calculation of CLK_DIV
public const uint TOTAL_MEM = 3; // Total available memory in 32-bit words

internal class NameConverter : DeviceNameConverter
{
public NameConverter()
: base(typeof(MemoryMonitor))
{
}
}
}
}
29 changes: 29 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/MemoryUsage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using Bonsai;

namespace OpenEphys.Onix
{
public class MemoryUsage : Source<MemoryUsageDataFrame>
{
[TypeConverter(typeof(MemoryMonitor.NameConverter))]
public string DeviceName { get; set; }

public override IObservable<MemoryUsageDataFrame> Generate()
{
return Observable.Using(
() => DeviceManager.ReserveDevice(DeviceName),
disposable => disposable.Subject.SelectMany(deviceInfo =>
{
var device = deviceInfo.GetDeviceContext(typeof(MemoryMonitor));
var totalMemory = device.ReadRegister(MemoryMonitor.TOTAL_MEM);

return deviceInfo.Context.FrameReceived
.Where(frame => frame.DeviceAddress == device.Address)
.Select(frame => new MemoryUsageDataFrame(frame, totalMemory));
}));
}
}
}
37 changes: 37 additions & 0 deletions OpenEphys.Onix/OpenEphys.Onix/MemoryUsageDataFrame.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Runtime.InteropServices;
using OpenCV.Net;

namespace OpenEphys.Onix
{
public class MemoryUsageDataFrame
{
public unsafe MemoryUsageDataFrame(oni.Frame frame, uint totalMemory)
{
var payload = (MemoryUsagePayload*)frame.Data.ToPointer();

FrameClock = frame.Clock;
DeviceAddress = frame.DeviceAddress;
HubClock = payload->HubClock;
PercentUsed = 100.0 * payload->Usage / totalMemory;
BytesUsed = payload->Usage * 4;

}

public ulong FrameClock { get; private set; }

public uint DeviceAddress { get; private set; }

public ulong HubClock { get; }

public double PercentUsed { get; }

public uint BytesUsed { get; }
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MemoryUsagePayload
{
public ulong HubClock;
public uint Usage;
}
}

0 comments on commit 0985fbb

Please sign in to comment.