Hash :
7181239d
Author :
Date :
2025-04-04T14:13:58
Add long ANGLE traces feature Enables very long Android captures by swapping binary data chunked buffers to/from disk. Bug: b/425728227 Change-Id: I539f72590eece03cfc69d42fc34be9825a9ff1fe Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6476924 Reviewed-by: Cody Northrop <cnorthrop@google.com> Commit-Queue: Mark Łobodziński <mark@lunarg.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
//
// Copyright 2025 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// frame_capture_binary_data.h:
// Common code for the ANGLE trace replay large trace binary data definition.
//
#ifndef FRAME_CAPTURE_BINARY_DATA_H_
#define FRAME_CAPTURE_BINARY_DATA_H_
#include "common/debug.h"
#include <stddef.h>
#include <fstream>
#include <vector>
namespace angle
{
constexpr size_t kDefaultBinaryDataSize = 0x80000000;
constexpr size_t kDefaultDataBlockSize = 256 * 1024 * 1024;
constexpr size_t kBinaryAlignment = 16;
// The zlib doc recommends buffer sizes on the order of 128K or 256K bytes
constexpr size_t kZlibBufferSize = 256 * 1024;
constexpr uint32_t kInvalidBlockId = 0xFFFFFFFF;
constexpr size_t kLongTraceVersionId = 1;
// Index information ultimately saved in trace JSON file
struct BinaryFileIndexInfo
{
size_t version; // Long file data description version number
size_t blockSize; // Size of binary data blocks in bytes
size_t blockCount; // Number of FileBlockInfo structures in file index trailer
size_t residentSize; // Max amount of device memory used for binary data storage
size_t indexOffset; // Offset in gzip file specifying start of file block descriptions
BinaryFileIndexInfo() : version(1), blockSize(0), blockCount(0), residentSize(0), indexOffset(0)
{}
};
class FileStream;
class FrameCaptureBinaryData
{
public:
enum class Mode
{
Load,
Store
};
// Describes a block's location in the binary data file
struct FileBlockInfo
{
size_t fileOffset; // Offset within the binary disk file
size_t dataOffset; // Starting offset in the logical flat data view
size_t dataSize; // Actual size of data in this block
FileBlockInfo() : fileOffset(0), dataOffset(0), dataSize(0) {}
};
// Describes a block's state during replay
struct ReplayBlockDescription
{
size_t fileOffset; // Seek offset in binary data disk file
size_t beginDataOffset; // Beginning flat binary data offset
size_t endDataOffset; // Ending flat binary data offset (inclusive)
size_t dataSize; // Size of data in this block
uint8_t *residentAddress; // Memory address if resident, nullptr otherwise
};
std::vector<std::vector<uint8_t>> &data() { return mData; }
bool isSwapBlock(size_t blockId) { return blockId == mMaxResidentBlockIndex; }
size_t totalSize() const;
bool isSwapMode() const;
bool isBlockResident(size_t blockId) const;
void setBlockResident(size_t blockId, uint8_t *address);
void setBlockNonResident(size_t blockId);
void setBinaryDataSize(size_t binaryDataSize);
void setBlockSize(size_t blockSize);
void storeResidentBlocks();
// Format data for appending to compressed binary file
BinaryFileIndexInfo appendFileIndex();
// Create binary memory block description index from binary file information
void constructBlockDescIndex(size_t indexOffset);
size_t append(const void *data, size_t size);
void clear();
const uint8_t *getData(size_t offset);
void initializeBinaryDataStore(bool compression,
const std::string &outDir,
const std::string &fileName);
void storeBlock();
BinaryFileIndexInfo closeBinaryDataStore();
void configureBinaryDataLoader(bool compression,
size_t blockCount,
size_t blockSize,
size_t residentSize,
size_t indexOffset,
const std::string &fileName);
void initializeBinaryDataLoader();
void loadBlock(size_t blockId);
void closeBinaryDataLoader();
void updateGetDataCache(size_t blockId);
std::vector<uint8_t> &prepareLoadBlock(size_t blockId);
std::vector<uint8_t> &prepareStoreBlock(size_t blockId);
private:
bool mIsBinaryDataCompressed;
std::string mFileName;
size_t mIndexOffset = 0;
std::vector<FileBlockInfo> mFileIndex;
uint32_t mStoredBlocks = 0;
size_t mCurrentTransientLoadedBlockId = kInvalidBlockId;
size_t mCurrentBlockOffset = 0;
size_t mMaxResidentBinarySize = kDefaultBinaryDataSize;
size_t mMaxResidentBlockIndex = (kDefaultBinaryDataSize / kDefaultDataBlockSize) - 1;
// Binary data information
size_t mDataBlockSize = kDefaultDataBlockSize;
size_t mBlockCount = 0;
// getData() fastpath cache information
size_t mCacheBlockId = kInvalidBlockId;
size_t mCacheBlockBeginOffset = 0;
size_t mCacheBlockEndOffset = 0;
uint8_t *mCacheBlockBaseAddress = nullptr;
std::vector<ReplayBlockDescription> mReplayBlockDescriptions;
// Chrome's allocator disallows creating one allocation that's bigger than 2GB, so the following
// is one large buffer that is split in multiple pieces in memory.
// Note: Make sure compression on write is disabled with a Chrome capture
// (ANGLE_CAPTURE_COMPRESSION=0), since that would require bundling all data in one big
// allocation.
std::vector<std::vector<uint8_t>> mData;
// Indicator that capture is complete and store can be finalized
bool mCaptureComplete = false;
FileStream *mFileStream = nullptr;
};
constexpr int kSeekBegin = SEEK_SET;
constexpr int kSeekEnd = SEEK_END;
class FileStream
{
public:
explicit FileStream(const std::string &filePath, FrameCaptureBinaryData::Mode mode)
: mMode(mode), mFile(nullptr), mFilePath(filePath)
{
std::string openMode;
if (mMode == FrameCaptureBinaryData::Mode::Store)
{
openMode = "wb+";
}
else if (mMode == FrameCaptureBinaryData::Mode::Load)
{
openMode = "rb";
}
else
{
FATAL() << "Invalid Mode enum in FileStream helper";
}
mFile = fopen(mFilePath.c_str(), openMode.c_str());
if (!mFile)
{
FATAL() << "Could not open binary data file " << mFilePath;
}
}
~FileStream()
{
if (mFile)
{
fclose(mFile);
mFile = nullptr;
}
}
void write(const uint8_t *data, size_t size);
size_t read(uint8_t *buffer, size_t size);
void seek(long long offset, int whence);
size_t getPosition();
private:
FrameCaptureBinaryData::Mode mMode;
FILE *mFile;
std::string mFilePath;
};
} // namespace angle
#endif // FRAME_CAPTURE_BINARY_DATA_H_