Add new malloc benchmarks.
This runs through the trace of the allocations in a sql benchmark app executed in the benchmark thread. Add one benchmark with decay time set to 0 and another with decay time set to 1. Include a script that can generate a header file that can be used to regenerate the data. Bug: 112317428 Test: Builds, ran unit tests, ran benchmarks. Change-Id: I62e287cc06b74b74bcc5a4bbee71b0fac0a196fd
This commit is contained in:
parent
5285d5995b
commit
0dc784431b
5 changed files with 535976 additions and 0 deletions
|
@ -29,6 +29,7 @@ cc_defaults {
|
|||
"bionic_benchmarks.cpp",
|
||||
"atomic_benchmark.cpp",
|
||||
"inttypes_benchmark.cpp",
|
||||
"malloc_benchmark.cpp",
|
||||
"math_benchmark.cpp",
|
||||
"property_benchmark.cpp",
|
||||
"pthread_benchmark.cpp",
|
||||
|
|
123
benchmarks/malloc_benchmark.cpp
Normal file
123
benchmarks/malloc_benchmark.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__BIONIC__)
|
||||
|
||||
enum AllocEnum : uint8_t {
|
||||
MALLOC = 0,
|
||||
CALLOC,
|
||||
MEMALIGN,
|
||||
REALLOC,
|
||||
FREE,
|
||||
};
|
||||
|
||||
struct MallocEntry {
|
||||
AllocEnum type;
|
||||
size_t idx;
|
||||
size_t size;
|
||||
size_t arg2;
|
||||
};
|
||||
|
||||
void BenchmarkMalloc(MallocEntry entries[], size_t total_entries, size_t max_allocs) {
|
||||
void* ptrs[max_allocs];
|
||||
|
||||
for (size_t i = 0; i < total_entries; i++) {
|
||||
switch (entries[i].type) {
|
||||
case MALLOC:
|
||||
ptrs[entries[i].idx] = malloc(entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 10;
|
||||
break;
|
||||
case CALLOC:
|
||||
ptrs[entries[i].idx] = calloc(entries[i].arg2, entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 20;
|
||||
break;
|
||||
case MEMALIGN:
|
||||
ptrs[entries[i].idx] = memalign(entries[i].arg2, entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 30;
|
||||
break;
|
||||
case REALLOC:
|
||||
if (entries[i].arg2 == 0) {
|
||||
ptrs[entries[i].idx] = realloc(nullptr, entries[i].size);
|
||||
} else {
|
||||
ptrs[entries[i].idx] = realloc(ptrs[entries[i].arg2 - 1], entries[i].size);
|
||||
}
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 40;
|
||||
break;
|
||||
case FREE:
|
||||
free(ptrs[entries[i].idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This codifies playing back a single threaded trace of the allocations
|
||||
// when running the SQLite BenchMark app.
|
||||
// Instructions for recreating:
|
||||
// - Enable malloc debug
|
||||
// setprop wrap.com.wtsang02.sqliteutil "LIBC_DEBUG_MALLOC_OPTIONS=record_allocs logwrapper"
|
||||
// - Start the SQLite BenchMark app
|
||||
// - Dump allocs using the signal to get rid of non sql allocs(kill -47 <SQLITE_PID>)
|
||||
// - Run the benchmark.
|
||||
// - Dump allocs using the signal again.
|
||||
// - Find the thread that has the most allocs and run the helper script
|
||||
// bionic/libc/malloc_debug/tools/gen_malloc.pl -i <THREAD_ID> g_sql_entries kMaxSqlAllocSlots < <ALLOC_FILE> > malloc_sql.h
|
||||
#include "malloc_sql.h"
|
||||
|
||||
static void BM_malloc_sql_trace_decay_time_0(benchmark::State& state) {
|
||||
mallopt(M_DECAY_TIME, 0);
|
||||
for (auto _ : state) {
|
||||
BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
|
||||
kMaxSqlAllocSlots);
|
||||
}
|
||||
}
|
||||
BIONIC_BENCHMARK(BM_malloc_sql_trace_decay_time_0);
|
||||
|
||||
static void BM_malloc_sql_trace_decay_time_1(benchmark::State& state) {
|
||||
mallopt(M_DECAY_TIME, 1);
|
||||
for (auto _ : state) {
|
||||
BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
|
||||
kMaxSqlAllocSlots);
|
||||
}
|
||||
}
|
||||
BIONIC_BENCHMARK(BM_malloc_sql_trace_decay_time_1);
|
||||
|
||||
#endif
|
535516
benchmarks/malloc_sql.h
Normal file
535516
benchmarks/malloc_sql.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -178,6 +178,8 @@ TEST_F(SystemTests, all_benchmarks) {
|
|||
"BM_atomic_store_seq_cst/iterations:1\n"
|
||||
"BM_inttypes_strtoimax/iterations:1\n"
|
||||
"BM_inttypes_strtoumax/iterations:1\n"
|
||||
"BM_malloc_sql_trace_decay_time_0/iterations:1\n"
|
||||
"BM_malloc_sql_trace_decay_time_1/iterations:1\n"
|
||||
"BM_math_cosf/0/iterations:1\n"
|
||||
"BM_math_cosf/1/iterations:1\n"
|
||||
"BM_math_cosf/2/iterations:1\n"
|
||||
|
|
334
libc/malloc_debug/tools/gen_malloc.pl
Executable file
334
libc/malloc_debug/tools/gen_malloc.pl
Executable file
|
@ -0,0 +1,334 @@
|
|||
#!/usr/bin/perl -w
|
||||
# Copyright (C) 2018 The Android Open Source Project
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
use strict;
|
||||
|
||||
sub PrintHeader() {
|
||||
print <<EOT;
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Generated by gen_malloc.pl, do not modify.
|
||||
|
||||
EOT
|
||||
}
|
||||
|
||||
sub PrintMainloop() {
|
||||
print <<EOT;
|
||||
void BenchmarkMalloc(MallocEntry entries[], size_t total_entries, size_t max_allocs) {
|
||||
void* ptrs[max_allocs];
|
||||
|
||||
for (size_t i = 0; i < total_entries; i++) {
|
||||
switch (entries[i].type) {
|
||||
case MALLOC:
|
||||
ptrs[entries[i].idx] = malloc(entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 10;
|
||||
break;
|
||||
case CALLOC:
|
||||
ptrs[entries[i].idx] = calloc(entries[i].arg2, entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 20;
|
||||
break;
|
||||
case MEMALIGN:
|
||||
ptrs[entries[i].idx] = memalign(entries[i].arg2, entries[i].size);
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 30;
|
||||
break;
|
||||
case REALLOC:
|
||||
if (entries[i].arg2 == 0) {
|
||||
ptrs[entries[i].idx] = realloc(nullptr, entries[i].size);
|
||||
} else {
|
||||
ptrs[entries[i].idx] = realloc(ptrs[entries[i].arg2 - 1], entries[i].size);
|
||||
}
|
||||
// Touch at least one byte of the allocation to make sure that
|
||||
// PSS for this allocation is counted.
|
||||
reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 40;
|
||||
break;
|
||||
case FREE:
|
||||
free(ptrs[entries[i].idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EOT
|
||||
}
|
||||
|
||||
sub PrintDefinitions() {
|
||||
print <<EOT;
|
||||
enum AllocEnum : uint8_t {
|
||||
MALLOC = 0,
|
||||
CALLOC,
|
||||
MEMALIGN,
|
||||
REALLOC,
|
||||
FREE,
|
||||
};
|
||||
|
||||
struct MallocEntry {
|
||||
AllocEnum type;
|
||||
size_t idx;
|
||||
size_t size;
|
||||
size_t arg2;
|
||||
};
|
||||
|
||||
EOT
|
||||
}
|
||||
|
||||
sub PrintUsageAndExit() {
|
||||
print "USAGE: gen_malloc.pl [-d][-i][-m] THREAD_ID STRUCT_NAME MAX_SLOT_NAME < ALLOCS.txt\n";
|
||||
print " -d\n";
|
||||
print " Print the structure definitions.\n";
|
||||
print " -i\n";
|
||||
print " Ignore missing allocations.\n";
|
||||
print " -m\n";
|
||||
print " Print the main loop code that can reproduce the trace.\n";
|
||||
print " THREAD_ID\n";
|
||||
print " The thread for which entries will be printed.\n";
|
||||
print " STRUCT_NAME\n";
|
||||
print " The name of the structure containing all of the entries.\n";
|
||||
print " MAX_SLOT_NAME\n";
|
||||
print " The name of the name of the maximum slots variable.\n";
|
||||
print " ALLOCS.txt\n";
|
||||
print " A file generated by the malloc debug option record_allocs\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub GetSlot($) {
|
||||
my ($opts) = @_;
|
||||
|
||||
if (scalar(@{$opts->{empty_slots}}) == 0) {
|
||||
return $opts->{last_slot}++;
|
||||
} else {
|
||||
return pop(@{$opts->{empty_slots}});
|
||||
}
|
||||
}
|
||||
|
||||
sub PrintFreeSlots($) {
|
||||
my ($opts) = @_;
|
||||
|
||||
if (scalar(@{$opts->{empty_slots}}) == $opts->{last_slot}) {
|
||||
return;
|
||||
}
|
||||
|
||||
print "\n // Free rest of the allocs.\n";
|
||||
my @sorted_empty_slots = sort({$a <=> $b} @{$opts->{empty_slots}});
|
||||
my $slot = 0;
|
||||
my $last_slot = $opts->{last_slot};
|
||||
while ($slot < $last_slot) {
|
||||
my $empty_slot = $last_slot;
|
||||
if (scalar(@sorted_empty_slots) != 0) {
|
||||
$empty_slot = shift(@sorted_empty_slots);
|
||||
}
|
||||
for (; $slot < $empty_slot; $slot++) {
|
||||
print " {FREE, $slot, 0, 0},\n";
|
||||
}
|
||||
$slot++;
|
||||
}
|
||||
}
|
||||
|
||||
sub PrintAlloc($$$$$$) {
|
||||
my ($opts, $cur_thread, $pointer, $name, $size, $arg2) = @_;
|
||||
|
||||
if ($opts->{thread} eq $cur_thread) {
|
||||
my $slot = GetSlot($opts);
|
||||
$opts->{pointers}->{$pointer} = $slot;
|
||||
print " {$name, $slot, $size, $arg2},\n";
|
||||
} else {
|
||||
$opts->{pointers}->{$pointer} = -1;
|
||||
}
|
||||
}
|
||||
|
||||
sub PrintEntries($$) {
|
||||
my ($thread, $ignore_missing_allocations) = @_;
|
||||
|
||||
my $opts = {};
|
||||
$opts->{thread} = $thread;
|
||||
$opts->{empty_slots} = [];
|
||||
$opts->{last_slot} = 0;
|
||||
$opts->{pointers} = {};
|
||||
|
||||
while (<>) {
|
||||
if (!/^(\d+):\s*/) {
|
||||
continue
|
||||
}
|
||||
my $cur_thread = $1;
|
||||
|
||||
$_ = $';
|
||||
if (/^malloc\s+(\S+)\s+(\d+)/) {
|
||||
my $pointer = $1;
|
||||
my $size = $2;
|
||||
PrintAlloc($opts, $cur_thread, $pointer, "MALLOC", $size, 0);
|
||||
} elsif (/^calloc\s+(\S+)\s+(\d+)\s+(\d+)/) {
|
||||
my $pointer = $1;
|
||||
my $nmemb = $2;
|
||||
my $size = $3;
|
||||
PrintAlloc($opts, $cur_thread, $pointer, "CALLOC", $size, $nmemb);
|
||||
} elsif (/^memalign\s+(\S+)\s+(\d+)\s+(\d+)/) {
|
||||
my $pointer = $1;
|
||||
my $align = $2;
|
||||
my $size = $3;
|
||||
PrintAlloc($opts, $cur_thread, $pointer, "MEMALIGN", $size, $align);
|
||||
} elsif (/^free\s+(\S+)/) {
|
||||
my $pointer = $1;
|
||||
if (!exists $opts->{pointers}->{$pointer}) {
|
||||
if ($ignore_missing_allocations) {
|
||||
warn "WARNING: $.: Unknown allocation $pointer ignored on $cur_thread\n";
|
||||
next;
|
||||
} else {
|
||||
die "$.: Unknown allocation $pointer on $cur_thread\n";
|
||||
}
|
||||
} elsif ($opts->{pointers}->{$pointer} != -1) {
|
||||
print " {FREE, $opts->{pointers}->{$pointer}, 0, 0},\n";
|
||||
push @{$opts->{empty_slots}}, $opts->{pointers}->{$pointer};
|
||||
}
|
||||
} elsif (/^realloc\s+(\S+)\s+(\S+)\s+(\d+)/) {
|
||||
my $new_pointer = $1;
|
||||
my $old_pointer = $2;
|
||||
my $size = $3;
|
||||
|
||||
if ($thread ne $cur_thread) {
|
||||
if ($new_pointer ne $old_pointer) {
|
||||
$opts->{pointers}->{$new_pointer} = -1;
|
||||
delete $opts->{pointers}->{$old_pointer};
|
||||
}
|
||||
} elsif ($old_pointer eq "0x0") {
|
||||
my $slot = GetSlot($opts);
|
||||
# This was a realloc(nullptr, size) call.
|
||||
print " {REALLOC, $slot, $size, 0},\n";
|
||||
$opts->{pointers}->{$new_pointer} = $slot;
|
||||
} else {
|
||||
if (!exists $opts->{pointers}->{$old_pointer}) {
|
||||
if ($ignore_missing_allocations) {
|
||||
warn "WARNING: $.: Unknown realloc allocation $old_pointer ignored on $cur_thread\n";
|
||||
next;
|
||||
} else {
|
||||
die "Unknown realloc allocation $old_pointer on $cur_thread\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($opts->{pointers}->{$old_pointer} != -1) {
|
||||
# Reuse the same slot, no need to get a new one.
|
||||
my $slot = $opts->{pointers}->{$old_pointer};
|
||||
printf(" {REALLOC, $slot, $size, %d},\n", $slot + 1);
|
||||
|
||||
# NOTE: It is possible that old pointer and new pointer are the
|
||||
# same (a realloc returns the same pointer).
|
||||
if ($new_pointer ne $old_pointer) {
|
||||
$opts->{pointers}->{$new_pointer} = $slot;
|
||||
delete $opts->{pointers}->{$old_pointer};
|
||||
}
|
||||
}
|
||||
}
|
||||
} elsif (!/^thread_done/) {
|
||||
die "$.: Unknown line $_\n";
|
||||
}
|
||||
}
|
||||
|
||||
PrintFreeSlots($opts);
|
||||
|
||||
return $opts->{last_slot};
|
||||
}
|
||||
|
||||
sub ProcessArgs($) {
|
||||
my ($opts) = @_;
|
||||
|
||||
$opts->{print_definitions} = 0;
|
||||
$opts->{ignore_missing_allocations} = 0;
|
||||
$opts->{print_mainloop} = 0;
|
||||
my @args = ();
|
||||
while (scalar(@ARGV)) {
|
||||
my $arg = pop(@ARGV);
|
||||
if ($arg =~ /^-/) {
|
||||
if ($arg eq "-d") {
|
||||
$opts->{print_definitions} = 1;
|
||||
} elsif ($arg eq "-i") {
|
||||
$opts->{ignore_missing_allocations} = 1;
|
||||
} elsif ($arg eq "-m") {
|
||||
$opts->{print_mainloop} = 1;
|
||||
} else {
|
||||
print "Unknown option $arg\n";
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
} else {
|
||||
unshift @args, $arg;
|
||||
}
|
||||
}
|
||||
|
||||
return @args;
|
||||
}
|
||||
|
||||
my $opts = {};
|
||||
my @args = ProcessArgs($opts);
|
||||
if (scalar(@args) != 3) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
|
||||
my $thread = $args[0];
|
||||
my $struct_name = $args[1];
|
||||
my $max_slot_name = $args[2];
|
||||
|
||||
PrintHeader();
|
||||
if ($opts->{print_definitions}) {
|
||||
PrintDefinitions();
|
||||
}
|
||||
if ($opts->{print_mainloop}) {
|
||||
PrintMainloop();
|
||||
}
|
||||
|
||||
print "static MallocEntry ${struct_name}[] = {\n";
|
||||
my $total_slots = PrintEntries($thread, $opts->{ignore_missing_allocations});
|
||||
print "};\n";
|
||||
print "static constexpr size_t ${max_slot_name} = $total_slots;\n";
|
Loading…
Reference in a new issue