28#include <arrow/memory_pool.h>
49std::atomic<int64_t> gCurrent{0};
50std::atomic<int64_t> gPeak{0};
51std::atomic<int64_t> gLargest{0};
59 auto now = gCurrent.fetch_add(
n) +
n;
60 for (
auto peak = gPeak.load();
now > peak && !gPeak.compare_exchange_weak(peak, now);) {
62 for (
auto largest = gLargest.load();
n > largest && !gLargest.compare_exchange_weak(largest,
n);) {
69 gCurrent.fetch_sub(malloc_usable_size(p));
91 track(p ? p : (
n ? nullptr : p));
109 return *out ? 0 : ENOMEM;
120constexpr int64_t kDecodeScratchBound = 9 * 1024 * 1024;
127int64_t valueAllocationBound(
int compress)
129 return compress / 100 == 2 ? kDecodeScratchBound : 640 * 1024;
136 start = gCurrent.load();
140 int64_t peakIncrease()
const {
return gPeak.load() -
start; }
141 int64_t retained()
const {
return gCurrent.load() -
start; }
146 std::ifstream status(
"/proc/self/status");
148 while (std::getline(status, line)) {
149 if (
line.starts_with(
"RssAnon:")) {
150 return std::stoll(
line.substr(8));
159 std::snprintf(
buf,
sizeof(
buf),
"%.2f MiB",
bytes / 1048576.);
166 explicit SharedBuffer(
size_t n) :
size(
std::
max<size_t>(
n, 1))
168 void*
p = mmap(
nullptr,
size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
169 if (p == MAP_FAILED) {
170 throw std::bad_alloc();
174 ~SharedBuffer() { munmap(
data,
size); }
181 std::vector<std::string> files;
182 for (
int i = 1;
i < argc; ++
i) {
183 if (std::strcmp(argv[
i],
"--threads") == 0 &&
i + 1 < argc) {
184 options.threads = std::stoi(argv[++
i]);
185 }
else if (std::strcmp(argv[
i],
"--pread") == 0) {
186 options.localIO = Options::LocalIO::PRead;
188 files.push_back(argv[
i]);
192 std::fprintf(stderr,
"usage: %s [--threads N] [--pread] <file>...\n", argv[0]);
196 std::printf(
"%-18s %-6s %11s %10s %10s %12s %13s %13s %15s %10s\n",
"file",
"DF",
"decoded",
"metadata",
"offsets",
197 "decode peak",
"values alloc",
"bools alloc",
"largest basket",
"RssAnon +");
198 for (
auto&
path : files) {
202 for (
auto& df : file.dataFrames()) {
203 auto rssBefore = rssAnonKiB();
205 std::vector<TreeInfo> trees;
206 for (
auto&
key : file.keysOf(df)) {
207 if (
key.className ==
"TTree") {
208 trees.push_back(file.readTree(
key));
211 auto metadataBytes = metadata.peakIncrease();
215 std::vector<std::vector<ColumnOp>> plans;
216 for (
auto&
tree : trees) {
220 auto offsetsBytes =
offsets.peakIncrease();
222 int64_t decodePeak = 0, valuesAlloc = 0, boolsAlloc = 0, decoded = 0;
223 uint32_t largestBasket = 0;
224 for (
auto& plan : plans) {
225 for (
auto&
op : plan) {
226 for (
auto&
b :
op.branch->baskets) {
227 largestBasket = std::max(largestBasket,
b.nbytes);
229 SharedBuffer out{
op.byteSize};
232 decodePeak = std::max(decodePeak,
decode.peakIncrease());
233 auto& largest =
op.kind == ColumnOp::Kind::Booleans ? boolsAlloc : valuesAlloc;
234 largest = std::max(largest, gLargest.load());
235 decoded +=
op.byteSize;
239 bool pread = options.localIO == Options::LocalIO::PRead;
240 int64_t inputAllowance = pread ? (
int64_t)options.threads * largestBasket : 0;
241 auto rssDelta = (rssAnonKiB() - rssBefore) * 1024;
242 std::string verdict =
"ok";
243 if (decodePeak > options.threads * kDecodeScratchBound + inputAllowance) {
244 verdict =
"FAIL: decode peak > " + mib(options.threads * kDecodeScratchBound + inputAllowance);
245 }
else if (!pread && valuesAlloc > valueAllocationBound(file.header().compress)) {
246 verdict =
"FAIL: value column allocation > " + mib(valueAllocationBound(file.header().compress));
248 std::printf(
"%-18s %-6s %11s %10s %10s %12s %13s %13s %15s %10s %s\n",
path.substr(
path.rfind(
'/') + 1).c_str(), df.c_str(),
249 mib(decoded).c_str(), mib(metadataBytes).c_str(), mib(offsetsBytes).c_str(), mib(decodePeak).c_str(),
250 mib(valuesAlloc).c_str(), mib(boolsAlloc).c_str(), mib(largestBasket).c_str(), mib(rssDelta).c_str(), verdict.c_str());
251 failures += verdict !=
"ok";
254 std::fprintf(stderr,
"%s: %s\n",
path.c_str(), e.what());
258 return failures ? 1 : 0;
static std::unique_ptr< ByteSource > open(std::string url, const Options &)
GLuint GLsizei const GLuint const GLintptr * offsets
GLboolean GLboolean GLboolean b
GLsizei GLsizei GLchar * source
GLsizei const GLchar *const * path
GLboolean GLboolean GLboolean GLboolean a
GLenum GLuint GLenum GLsizei const GLchar * buf
std::shared_ptr< arrow::Schema > datasetSchema(std::shared_ptr< arrow::Schema > const &physical)
The physical schema without the *_size fields, as DataInputDirector derives it.
std::shared_ptr< arrow::Schema > physicalSchema(TreeInfo const &tree)
std::vector< ColumnOp > planColumns(TreeInfo const &tree, std::shared_ptr< arrow::Schema > const &schema, BranchDecoder &decoder, arrow::MemoryPool *pool, int64_t &rows)
void executeColumnOp(BranchDecoder &decoder, ColumnOp const &op, uint8_t *dst)
Fills the buffer of op, which is exactly op.byteSize bytes.
uint8_t itsSharedClusterMap uint8_t
int32_t const char int32_t line
const bool const int TrackITSInternal< NLayers > & track
int posix_memalign(void **out, size_t a, size_t n)
void * realloc(void *old, size_t n)
void * __libc_malloc(size_t)
void * __libc_memalign(size_t, size_t)
void * calloc(size_t a, size_t b)
void * aligned_alloc(size_t a, size_t n)
void * __libc_realloc(void *, size_t)
void * memalign(size_t a, size_t n)
void * __libc_calloc(size_t, size_t)
coder decode(ctfImage, triggersD, clustersD)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< ReadoutWindowData > rows