You can’t exactly measure the specific I/O cost as files can be in many places on the target drive & file transfers are the slowest operation when it comes to retrieving data.
You can use the size map to narrow down the largest assets and consider some form of optimizations for them
The size map != load time though, just a rough estimate of the weight of the asset that can increase load times.
Otherwise you could for instance have an array of objects and load them all up and save the microtime difference between the start and end of the loading. You could put the output into a struct and then sort it via asset load time and save it to a file.
Depending on the CPU side you might also just not have enough free resources to process the assets in a timely manner.
You could also consider moving I/O tasks into an FRunnable separate thread that could offload any file transfer blockage.
Looking into the source code that drives the FGenericBaseRequest that is called during the io thread creation it does have a delegate called on completion:
FAsyncFileCallBack* CompleteCallback
passed in as one of the parameters.
In theory you could hook into this callback delegate and use it’s call to know what I/O async process finished. Though it may require some custom inherited classes to expose the delegate
At a glance the GenericPlatformFile.cpp seems to be responsible for producing the I/O background tasks, though no completion delegate is exposed for custom hooks.
Which function are you using to invoke the I/O operation? Check if it has a completion delegate built in.