Add StatusReportService

This commit is contained in:
Alex Barney 2021-01-29 17:41:12 -07:00
parent e5291eb06a
commit 2f9fbdb818
10 changed files with 309 additions and 74 deletions

View file

@ -5,17 +5,16 @@ namespace LibHac.Fs
[StructLayout(LayoutKind.Sequential, Size = 0x80)]
public struct MemoryReportInfo
{
long PooledBufferFreeSizePeak;
long PooledBufferRetriedCount;
long PooledBufferReduceAllocationCount;
long BufferManagerFreeSizePeak;
long BufferManagerRetiredCount;
long ExpHeapFreeSizePeak;
long BufferPoolFreeSizePeak;
long PatrolAllocateSuccessCount;
long PatrolAllocateFailureCount;
long BufferManagerTotalAllocatableSizePeak;
long BufferPoolAllocateSizeMax;
};
public long PooledBufferFreeSizePeak;
public long PooledBufferRetriedCount;
public long PooledBufferReduceAllocationCount;
public long BufferManagerFreeSizePeak;
public long BufferManagerRetriedCount;
public long ExpHeapFreeSizePeak;
public long BufferPoolFreeSizePeak;
public long PatrolAllocateSuccessCount;
public long PatrolAllocateFailureCount;
public long BufferManagerTotalAllocatableSizePeak;
public long BufferPoolAllocateSizeMax;
}
}

View file

@ -9,4 +9,6 @@ namespace LibHac.FsSrv
public delegate Result SaveTransferCmacGenerator(Span<byte> mac, ReadOnlySpan<byte> data,
SaveDataTransferCryptoConfiguration.KeyIndex index, int keyGeneration);
public delegate Result PatrolAllocateCountGetter(out long successCount, out long failureCount);
}

View file

@ -10,6 +10,7 @@ namespace LibHac.FsSrv
public NcaFileSystemServiceImpl NcaFileSystemService { get; set; }
public SaveDataFileSystemServiceImpl SaveDataFileSystemService { get; set; }
public TimeServiceImpl TimeService { get; set; }
public StatusReportServiceImpl StatusReportService { get; set; }
public ProgramRegistryServiceImpl ProgramRegistryService { get; set; }
public AccessLogServiceImpl AccessLogService { get; set; }
}

View file

@ -28,6 +28,65 @@ namespace LibHac.FsSrv
CurrentProcess = ulong.MaxValue;
}
private Result GetProgramInfo(out ProgramInfo programInfo)
{
return FsProxyCore.ProgramRegistry.GetProgramInfo(out programInfo, CurrentProcess);
}
private Result GetNcaFileSystemService(out NcaFileSystemService ncaFsService)
{
if (NcaFsService is null)
{
ncaFsService = null;
return ResultFs.PreconditionViolation.Log();
}
ncaFsService = NcaFsService.Target;
return Result.Success;
}
private Result GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService)
{
if (SaveFsService is null)
{
saveFsService = null;
return ResultFs.PreconditionViolation.Log();
}
saveFsService = SaveFsService.Target;
return Result.Success;
}
private BaseStorageService GetBaseStorageService()
{
return new BaseStorageService(FsProxyCore.Config.BaseStorageService, CurrentProcess);
}
private BaseFileSystemService GetBaseFileSystemService()
{
return new BaseFileSystemService(FsProxyCore.Config.BaseFileSystemService, CurrentProcess);
}
private TimeService GetTimeService()
{
return new TimeService(FsProxyCore.Config.TimeService, CurrentProcess);
}
private StatusReportService GetStatusReportService()
{
return new StatusReportService(FsProxyCore.Config.StatusReportService);
}
private ProgramIndexRegistryService GetProgramIndexRegistryService()
{
return new ProgramIndexRegistryService(FsProxyCore.Config.ProgramRegistryService, CurrentProcess);
}
private AccessLogService GetAccessLogService()
{
return new AccessLogService(FsProxyCore.Config.AccessLogService, CurrentProcess);
}
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path,
ulong id, FileSystemProxyType fsType)
{
@ -863,7 +922,7 @@ namespace LibHac.FsSrv
public Result GetAndClearErrorInfo(out FileSystemProxyErrorInfo errorInfo)
{
throw new NotImplementedException();
return GetStatusReportService().GetAndClearFileSystemProxyErrorInfo(out errorInfo);
}
public Result RegisterProgramIndexMapInfo(InBuffer programIndexMapInfoBuffer, int programCount)
@ -984,14 +1043,14 @@ namespace LibHac.FsSrv
return ncaFsService.OpenRegisteredUpdatePartition(out fileSystem);
}
public Result GetAndClearMemoryReportInfo(out MemoryReportInfo report)
public Result GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo)
{
throw new NotImplementedException();
return GetStatusReportService().GetAndClearMemoryReportInfo(out reportInfo);
}
public Result GetFsStackUsage(out uint stackUsage, FsStackUsageThreadType threadType)
{
throw new NotImplementedException();
return GetStatusReportService().GetFsStackUsage(out stackUsage, threadType);
}
public Result OverrideSaveDataTransferTokenSignVerificationKey(InBuffer key)
@ -1058,59 +1117,5 @@ namespace LibHac.FsSrv
{
return GetBaseFileSystemService().OpenBisWiper(out bisWiper, transferMemoryHandle, transferMemorySize);
}
private Result GetProgramInfo(out ProgramInfo programInfo)
{
return FsProxyCore.ProgramRegistry.GetProgramInfo(out programInfo, CurrentProcess);
}
private Result GetNcaFileSystemService(out NcaFileSystemService ncaFsService)
{
if (NcaFsService is null)
{
ncaFsService = null;
return ResultFs.PreconditionViolation.Log();
}
ncaFsService = NcaFsService.Target;
return Result.Success;
}
private Result GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService)
{
if (SaveFsService is null)
{
saveFsService = null;
return ResultFs.PreconditionViolation.Log();
}
saveFsService = SaveFsService.Target;
return Result.Success;
}
private BaseStorageService GetBaseStorageService()
{
return new BaseStorageService(FsProxyCore.Config.BaseStorageService, CurrentProcess);
}
private BaseFileSystemService GetBaseFileSystemService()
{
return new BaseFileSystemService(FsProxyCore.Config.BaseFileSystemService, CurrentProcess);
}
private TimeService GetTimeService()
{
return new TimeService(FsProxyCore.Config.TimeService, CurrentProcess);
}
private ProgramIndexRegistryService GetProgramIndexRegistryService()
{
return new ProgramIndexRegistryService(FsProxyCore.Config.ProgramRegistryService, CurrentProcess);
}
private AccessLogService GetAccessLogService()
{
return new AccessLogService(FsProxyCore.Config.AccessLogService, CurrentProcess);
}
}
}

View file

@ -1,10 +1,12 @@
using System;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Fs.Impl;
using LibHac.Fs.Shim;
using LibHac.FsSrv.Creators;
using LibHac.FsSrv.Impl;
using LibHac.FsSrv.Sf;
using LibHac.FsSrv.Storage;
using LibHac.Sm;
namespace LibHac.FsSrv
@ -17,6 +19,7 @@ namespace LibHac.FsSrv
private const ulong SpeedEmulationProgramIdMaximum = 0x100000000001FFF;
private FileSystemProxyCoreImpl FsProxyCore { get; }
public StorageService Storage { get; }
/// <summary>The client instance to be used for internal operations like save indexer access.</summary>
public HorizonClient Hos { get; }
@ -48,6 +51,8 @@ namespace LibHac.FsSrv
Hos = horizonClient;
Storage = new StorageService(this);
IsDebugMode = false;
Timer = config.TimeSpanGenerator ?? new StopWatchTimeSpanGenerator();
@ -155,6 +160,19 @@ namespace LibHac.FsSrv
var saveFsService = new SaveDataFileSystemServiceImpl(in saveFsServiceConfig);
var statusReportServiceConfig = new StatusReportServiceImpl.Configuration();
statusReportServiceConfig.NcaFsServiceImpl = ncaFsService;
statusReportServiceConfig.SaveFsServiceImpl = saveFsService;
statusReportServiceConfig.BufferManagerMemoryReport = null;
statusReportServiceConfig.ExpHeapMemoryReport = null;
statusReportServiceConfig.BufferPoolMemoryReport = null;
statusReportServiceConfig.GetPatrolAllocateCounts = null;
statusReportServiceConfig.MainThreadStackUsageReporter = new DummyStackUsageReporter();
statusReportServiceConfig.IpcWorkerThreadStackUsageReporter = new DummyStackUsageReporter();
statusReportServiceConfig.PipeLineWorkerThreadStackUsageReporter = new DummyStackUsageReporter();
var statusReportService = new StatusReportServiceImpl(in statusReportServiceConfig);
var accessLogServiceConfig = new AccessLogServiceImpl.Configuration();
accessLogServiceConfig.MinimumProgramIdForSdCardLog = 0x0100000000003000;
accessLogServiceConfig.HorizonClient = Hos;
@ -169,6 +187,7 @@ namespace LibHac.FsSrv
NcaFileSystemService = ncaFsService,
SaveDataFileSystemService = saveFsService,
TimeService = timeService,
StatusReportService = statusReportService,
ProgramRegistryService = programRegistryService,
AccessLogService = accessLogService
};
@ -238,6 +257,11 @@ namespace LibHac.FsSrv
return Result.Success;
}
}
private class DummyStackUsageReporter : IStackUsageReporter
{
public uint GetStackUsage() => 0;
}
}
/// <summary>
@ -268,6 +292,31 @@ namespace LibHac.FsSrv
public ITimeSpanGenerator TimeSpanGenerator { get; set; }
}
public class StorageService
{
internal FileSystemServer Fs;
private IStorageDeviceManagerFactory _factory;
internal StorageService(FileSystemServer parentServer)
{
Fs = parentServer;
}
public void SetStorageDeviceManagerFactory(IStorageDeviceManagerFactory factory)
{
Assert.NotNull(factory);
Assert.Null(_factory);
_factory = factory;
}
public IStorageDeviceManagerFactory GetStorageDeviceManagerFactory()
{
Assert.NotNull(_factory);
return _factory;
}
}
// Functions in the nn::fssrv::detail namespace use this struct.
// Possibly move this to the main class if the separation doesn't seem necessary.
internal struct FileSystemServerImpl

View file

@ -0,0 +1,7 @@
namespace LibHac.FsSrv
{
public interface IStackUsageReporter
{
uint GetStackUsage();
}
}

View file

@ -0,0 +1,11 @@
namespace LibHac.FsSrv
{
public abstract class MemoryReport
{
public abstract long GetFreeSizePeak();
public abstract long GetTotalAllocatableSizePeak();
public abstract long GetRetriedCount();
public abstract long GetAllocateSizeMax();
public abstract void Clear();
}
}

View file

@ -612,9 +612,23 @@ namespace LibHac.FsSrv
return programId;
}
public void ResetTemporaryStorageIndexer()
public Result GetSaveDataIndexCount(out int count)
{
_config.SaveIndexerManager.ResetIndexer(SaveDataSpaceId.Temporary);
Unsafe.SkipInit(out count);
SaveDataIndexerAccessor accessor = null;
try
{
Result rc = OpenSaveDataIndexerAccessor(out accessor, out bool _, SaveDataSpaceId.User);
if (rc.IsFailure()) return rc;
count = accessor.Indexer.GetIndexCount();
return Result.Success;
}
finally
{
accessor?.Dispose();
}
}
public Result OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit,
@ -622,5 +636,10 @@ namespace LibHac.FsSrv
{
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(out accessor, out neededInit, spaceId);
}
public void ResetTemporaryStorageIndexer()
{
_config.SaveIndexerManager.ResetIndexer(SaveDataSpaceId.Temporary);
}
}
}

View file

@ -114,7 +114,7 @@ namespace LibHac.FsSrv.Sf
Result OutputAccessLogToSdCard(InBuffer textBuffer);
Result RegisterUpdatePartition();
Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystemSf> fileSystem);
Result GetAndClearMemoryReportInfo(out MemoryReportInfo report);
Result GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo);
Result GetProgramIndexForAccessLog(out int programIndex, out int programCount);
Result GetFsStackUsage(out uint stackUsage, FsStackUsageThreadType threadType);
Result UnsetSaveDataRootPath();

View file

@ -0,0 +1,142 @@
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Os;
namespace LibHac.FsSrv
{
public readonly struct StatusReportService
{
private readonly StatusReportServiceImpl _serviceImpl;
public StatusReportService(StatusReportServiceImpl serviceImpl)
{
_serviceImpl = serviceImpl;
}
public Result GetAndClearFileSystemProxyErrorInfo(out FileSystemProxyErrorInfo errorInfo)
{
return _serviceImpl.GetAndClearFileSystemProxyErrorInfo(out errorInfo);
}
public Result GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo)
{
return _serviceImpl.GetAndClearMemoryReportInfo(out reportInfo);
}
public Result GetFsStackUsage(out uint stackUsage, FsStackUsageThreadType threadType)
{
stackUsage = _serviceImpl.ReportStackUsage(threadType);
return Result.Success;
}
}
public class StatusReportServiceImpl
{
private Configuration _config;
private SdkMutexType _mutex;
public StatusReportServiceImpl(in Configuration configuration)
{
_config = configuration;
_mutex.Initialize();
}
public struct Configuration
{
public NcaFileSystemServiceImpl NcaFsServiceImpl;
public SaveDataFileSystemServiceImpl SaveFsServiceImpl;
// Missing: FatFileSystemCreator (Not an IFatFileSystemCreator)
public MemoryReport BufferManagerMemoryReport;
public MemoryReport ExpHeapMemoryReport;
public MemoryReport BufferPoolMemoryReport;
public PatrolAllocateCountGetter GetPatrolAllocateCounts;
public IStackUsageReporter MainThreadStackUsageReporter;
public IStackUsageReporter IpcWorkerThreadStackUsageReporter;
public IStackUsageReporter PipeLineWorkerThreadStackUsageReporter;
public FileSystemServer FsServer;
}
public Result GetAndClearFileSystemProxyErrorInfo(out FileSystemProxyErrorInfo errorInfo)
{
errorInfo = new FileSystemProxyErrorInfo();
_config.NcaFsServiceImpl.GetAndClearRomFsErrorInfo(out errorInfo.RomFsRemountForDataCorruptionCount,
out errorInfo.RomFsUnrecoverableDataCorruptionByRemountCount,
out errorInfo.RomFsRecoveredByInvalidateCacheCount);
// Missing: GetFatInfo
Result rc = _config.SaveFsServiceImpl.GetSaveDataIndexCount(out int count);
if (rc.IsFailure()) return rc;
errorInfo.SaveDataIndexCount = count;
return Result.Success;
}
public Result GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo)
{
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
reportInfo = new MemoryReportInfo();
// Missing: Get and clear pooled buffer stats
reportInfo.PooledBufferFreeSizePeak = 0;
reportInfo.PooledBufferRetriedCount = 0;
reportInfo.PooledBufferReduceAllocationCount = 0;
MemoryReport report = _config.BufferManagerMemoryReport;
if (report != null)
{
reportInfo.BufferManagerFreeSizePeak = report.GetFreeSizePeak();
reportInfo.BufferManagerTotalAllocatableSizePeak = report.GetTotalAllocatableSizePeak();
reportInfo.BufferManagerRetriedCount = report.GetRetriedCount();
report.Clear();
}
report = _config.ExpHeapMemoryReport;
if (report != null)
{
reportInfo.ExpHeapFreeSizePeak = report.GetFreeSizePeak();
report.Clear();
}
report = _config.BufferPoolMemoryReport;
if (report != null)
{
reportInfo.BufferPoolFreeSizePeak = report.GetFreeSizePeak();
reportInfo.BufferPoolAllocateSizeMax = report.GetAllocateSizeMax();
report.Clear();
}
if (_config.GetPatrolAllocateCounts != null)
{
_config.GetPatrolAllocateCounts(out reportInfo.PatrolAllocateSuccessCount,
out reportInfo.PatrolAllocateFailureCount);
}
return Result.Success;
}
public uint ReportStackUsage(FsStackUsageThreadType threadType)
{
switch (threadType)
{
case FsStackUsageThreadType.MainThread:
Assert.NotNull(_config.MainThreadStackUsageReporter);
return _config.MainThreadStackUsageReporter.GetStackUsage();
case FsStackUsageThreadType.IpcWorker:
Assert.NotNull(_config.IpcWorkerThreadStackUsageReporter);
return _config.IpcWorkerThreadStackUsageReporter.GetStackUsage();
case FsStackUsageThreadType.PipelineWorker:
Assert.NotNull(_config.PipeLineWorkerThreadStackUsageReporter);
return _config.PipeLineWorkerThreadStackUsageReporter.GetStackUsage();
default:
return 0;
}
}
}
}